KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > compare > internal > CompareUIPlugin


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.compare.internal;
12
13 import java.io.*;
14 import java.lang.reflect.InvocationTargetException JavaDoc;
15 import java.net.URL JavaDoc;
16 import java.util.*;
17 import java.util.List JavaDoc;
18
19 import org.eclipse.compare.*;
20 import org.eclipse.compare.structuremergeviewer.*;
21 import org.eclipse.core.runtime.*;
22 import org.eclipse.core.runtime.content.IContentType;
23 import org.eclipse.core.runtime.content.IContentTypeManager;
24 import org.eclipse.jface.dialogs.MessageDialog;
25 import org.eclipse.jface.operation.IRunnableContext;
26 import org.eclipse.jface.preference.IPreferenceStore;
27 import org.eclipse.jface.resource.ImageDescriptor;
28 import org.eclipse.jface.util.IPropertyChangeListener;
29 import org.eclipse.jface.util.PropertyChangeEvent;
30 import org.eclipse.jface.viewers.Viewer;
31 import org.eclipse.swt.graphics.Image;
32 import org.eclipse.swt.widgets.*;
33 import org.eclipse.ui.*;
34 import org.eclipse.ui.model.IWorkbenchAdapter;
35 import org.eclipse.ui.plugin.AbstractUIPlugin;
36 import org.osgi.framework.BundleContext;
37
38
39 /**
40  * The Compare UI plug-in defines the entry point to initiate a configurable
41  * compare operation on arbitrary resources. The result of the compare
42  * is opened into a compare editor where the details can be browsed and
43  * edited in dynamically selected structure and content viewers.
44  * <p>
45  * The Compare UI provides a registry for content and structure compare viewers,
46  * which is initialized from extensions contributed to extension points
47  * declared by this plug-in.
48  * <p>
49  * This class is the plug-in runtime class for the
50  * <code>"org.eclipse.compare"</code> plug-in.
51  * </p>
52  */

53 public final class CompareUIPlugin extends AbstractUIPlugin {
54     
55     static class CompareRegistry {
56         
57             private final static String JavaDoc ID_ATTRIBUTE= "id"; //$NON-NLS-1$
58
private final static String JavaDoc EXTENSIONS_ATTRIBUTE= "extensions"; //$NON-NLS-1$
59
private final static String JavaDoc CONTENT_TYPE_ID_ATTRIBUTE= "contentTypeId"; //$NON-NLS-1$
60

61             private HashMap fIdMap; // maps ids to data
62
private HashMap fExtensionMap; // maps extensions to data
63
private HashMap fContentTypeBindings; // maps content type bindings to data
64

65  
66             void register(IConfigurationElement element, Object JavaDoc data) {
67                 String JavaDoc id= element.getAttribute(ID_ATTRIBUTE);
68                 if (id != null) {
69                     if (fIdMap == null)
70                         fIdMap= new HashMap();
71                     fIdMap.put(id, data);
72                 }
73                 
74                 String JavaDoc types= element.getAttribute(EXTENSIONS_ATTRIBUTE);
75                 if (types != null) {
76                     if (fExtensionMap == null)
77                         fExtensionMap= new HashMap();
78                     StringTokenizer tokenizer= new StringTokenizer(types, ","); //$NON-NLS-1$
79
while (tokenizer.hasMoreElements()) {
80                         String JavaDoc extension= tokenizer.nextToken().trim();
81                         fExtensionMap.put(normalizeCase(extension), data);
82                     }
83                 }
84             }
85
86             void createBinding(IConfigurationElement element, String JavaDoc idAttributeName) {
87             String JavaDoc type= element.getAttribute(CONTENT_TYPE_ID_ATTRIBUTE);
88             String JavaDoc id= element.getAttribute(idAttributeName);
89             if (id == null)
90                 logErrorMessage(Utilities.getFormattedString("CompareUIPlugin.targetIdAttributeMissing", idAttributeName)); //$NON-NLS-1$
91
if (type != null && id != null && fIdMap != null) {
92                 Object JavaDoc o= fIdMap.get(id);
93                 if (o != null) {
94                     IContentType ct= fgContentTypeManager.getContentType(type);
95                     if (ct != null) {
96                         if (fContentTypeBindings == null)
97                             fContentTypeBindings= new HashMap();
98                         fContentTypeBindings.put(ct, o);
99                     } else {
100                         logErrorMessage(Utilities.getFormattedString("CompareUIPlugin.contentTypeNotFound", type)); //$NON-NLS-1$
101
}
102                 } else {
103                     logErrorMessage(Utilities.getFormattedString("CompareUIPlugin.targetNotFound", id)); //$NON-NLS-1$
104
}
105             }
106             }
107
108             Object JavaDoc search(IContentType type) {
109                 if (fContentTypeBindings != null) {
110                         for (; type != null; type= type.getBaseType()) {
111                             Object JavaDoc data= fContentTypeBindings.get(type);
112                             if (data != null)
113                                 return data;
114                         }
115                 }
116                 return null;
117             }
118             
119             Object JavaDoc search(String JavaDoc extension) {
120                 if (fExtensionMap != null)
121                     return fExtensionMap.get(normalizeCase(extension));
122                 return null;
123             }
124     }
125     
126     /** Status code describing an internal error */
127     public static final int INTERNAL_ERROR= 1;
128
129     private static boolean NORMALIZE_CASE= true;
130
131     public static final String JavaDoc PLUGIN_ID= "org.eclipse.compare"; //$NON-NLS-1$
132

133     private static final String JavaDoc BINARY_TYPE= "binary"; //$NON-NLS-1$
134

135     private static final String JavaDoc STREAM_MERGER_EXTENSION_POINT= "streamMergers"; //$NON-NLS-1$
136
private static final String JavaDoc STREAM_MERGER= "streamMerger"; //$NON-NLS-1$
137
private static final String JavaDoc STREAM_MERGER_ID_ATTRIBUTE= "streamMergerId"; //$NON-NLS-1$
138
private static final String JavaDoc STRUCTURE_CREATOR_EXTENSION_POINT= "structureCreators"; //$NON-NLS-1$
139
private static final String JavaDoc STRUCTURE_CREATOR= "structureCreator"; //$NON-NLS-1$
140
private static final String JavaDoc STRUCTURE_CREATOR_ID_ATTRIBUTE= "structureCreatorId"; //$NON-NLS-1$
141

142     private static final String JavaDoc VIEWER_TAG= "viewer"; //$NON-NLS-1$
143
private static final String JavaDoc STRUCTURE_MERGE_VIEWER_EXTENSION_POINT= "structureMergeViewers"; //$NON-NLS-1$
144
private static final String JavaDoc STRUCTURE_MERGE_VIEWER_ID_ATTRIBUTE= "structureMergeViewerId"; //$NON-NLS-1$
145
private static final String JavaDoc CONTENT_MERGE_VIEWER_EXTENSION_POINT= "contentMergeViewers"; //$NON-NLS-1$
146
private static final String JavaDoc CONTENT_MERGE_VIEWER_ID_ATTRIBUTE= "contentMergeViewerId"; //$NON-NLS-1$
147
private static final String JavaDoc CONTENT_VIEWER_EXTENSION_POINT= "contentViewers"; //$NON-NLS-1$
148
private static final String JavaDoc CONTENT_VIEWER_ID_ATTRIBUTE= "contentViewerId"; //$NON-NLS-1$
149

150     private static final String JavaDoc CONTENT_TYPE_BINDING= "contentTypeBinding"; //$NON-NLS-1$
151

152
153     private static final String JavaDoc COMPARE_EDITOR= PLUGIN_ID + ".CompareEditor"; //$NON-NLS-1$
154

155     private static final String JavaDoc STRUCTUREVIEWER_ALIASES_PREFERENCE_NAME= "StructureViewerAliases"; //$NON-NLS-1$
156

157     // content type
158
private static final IContentTypeManager fgContentTypeManager= Platform.getContentTypeManager();
159
160     public static final int NO_DIFFERENCE = 10000;
161
162     /**
163      * The plugin singleton.
164      */

165     private static CompareUIPlugin fgComparePlugin;
166     
167     /** Maps type to icons */
168     private static Map fgImages= new Hashtable(10);
169     /** Maps type to ImageDescriptors */
170     private static Map fgImageDescriptors= new Hashtable(10);
171     /** Maps ImageDescriptors to Images */
172     private static Map fgImages2= new Hashtable(10);
173     
174     private static List JavaDoc fgDisposeOnShutdownImages= new ArrayList();
175     
176     private ResourceBundle fResourceBundle;
177
178     private boolean fRegistriesInitialized;
179     private CompareRegistry fStreamMergers= new CompareRegistry();
180     private CompareRegistry fStructureCreators= new CompareRegistry();
181     private CompareRegistry fStructureMergeViewers= new CompareRegistry();
182     private CompareRegistry fContentViewers= new CompareRegistry();
183     private CompareRegistry fContentMergeViewers= new CompareRegistry();
184
185     private Map fStructureViewerAliases;
186     private CompareFilter fFilter;
187     private IPropertyChangeListener fPropertyChangeListener;
188     private boolean useOldDifferencer = false;
189     
190     /**
191      * Creates the <code>CompareUIPlugin</code> object and registers all
192      * structure creators, content merge viewers, and structure merge viewers
193      * contributed to this plug-in's extension points.
194      * <p>
195      * Note that instances of plug-in runtime classes are automatically created
196      * by the platform in the course of plug-in activation.
197      */

198     public CompareUIPlugin() {
199         super();
200         Assert.isTrue(fgComparePlugin == null);
201         fgComparePlugin= this;
202     }
203
204     public void start(BundleContext context) throws Exception JavaDoc {
205         super.start(context);
206     }
207             
208     public void stop(BundleContext context) throws Exception JavaDoc {
209         
210         IPreferenceStore ps= getPreferenceStore();
211         rememberAliases(ps);
212         if (fPropertyChangeListener != null) {
213             ps.removePropertyChangeListener(fPropertyChangeListener);
214             fPropertyChangeListener= null;
215         }
216         
217         super.stop(context);
218         
219         if (fgDisposeOnShutdownImages != null) {
220             Iterator i= fgDisposeOnShutdownImages.iterator();
221             while (i.hasNext()) {
222                 Image img= (Image) i.next();
223                 if (!img.isDisposed())
224                     img.dispose();
225             }
226             fgImages= null;
227         }
228     }
229         
230     /**
231      * Returns the singleton instance of this plug-in runtime class.
232      *
233      * @return the compare plug-in instance
234      */

235     public static CompareUIPlugin getDefault() {
236         return fgComparePlugin;
237     }
238     
239     /**
240      * Returns this plug-in's resource bundle.
241      *
242      * @return the plugin's resource bundle
243      */

244     public ResourceBundle getResourceBundle() {
245         if (fResourceBundle == null)
246             fResourceBundle= Platform.getResourceBundle(getBundle());
247         return fResourceBundle;
248     }
249     
250     /**
251      * Returns this plug-in's unique identifier.
252      *
253      * @return the plugin's unique identifier
254      */

255     public static String JavaDoc getPluginId() {
256         return getDefault().getBundle().getSymbolicName();
257     }
258
259     private void initializeRegistries() {
260         if (!fRegistriesInitialized) {
261             registerExtensions();
262             fRegistriesInitialized= true;
263         }
264     }
265     
266     /**
267      * Registers all stream mergers, structure creators, content merge viewers, and structure merge viewers
268      * that are found in the XML plugin files.
269      */

270     private void registerExtensions() {
271         IExtensionRegistry registry= Platform.getExtensionRegistry();
272         
273         // collect all IStreamMergers
274
IConfigurationElement[] elements= registry.getConfigurationElementsFor(PLUGIN_ID, STREAM_MERGER_EXTENSION_POINT);
275         for (int i= 0; i < elements.length; i++) {
276             IConfigurationElement element= elements[i];
277                 if (STREAM_MERGER.equals(element.getName()))
278                 fStreamMergers.register(element, new StreamMergerDescriptor(element));
279         }
280         for (int i= 0; i < elements.length; i++) {
281             IConfigurationElement element= elements[i];
282                 if (CONTENT_TYPE_BINDING.equals(element.getName()))
283                     fStreamMergers.createBinding(element, STREAM_MERGER_ID_ATTRIBUTE);
284         }
285                 
286         // collect all IStructureCreators
287
elements= registry.getConfigurationElementsFor(PLUGIN_ID, STRUCTURE_CREATOR_EXTENSION_POINT);
288         for (int i= 0; i < elements.length; i++) {
289             IConfigurationElement element= elements[i];
290             String JavaDoc name= element.getName();
291             if (!CONTENT_TYPE_BINDING.equals(name)) {
292                 if (!STRUCTURE_CREATOR.equals(name))
293                     logErrorMessage(Utilities.getFormattedString("CompareUIPlugin.unexpectedTag", name, STRUCTURE_CREATOR)); //$NON-NLS-1$
294
fStructureCreators.register(element, new StructureCreatorDescriptor(element));
295             }
296         }
297         for (int i= 0; i < elements.length; i++) {
298             IConfigurationElement element= elements[i];
299             if (CONTENT_TYPE_BINDING.equals(element.getName()))
300                 fStructureCreators.createBinding(element, STRUCTURE_CREATOR_ID_ATTRIBUTE);
301         }
302                 
303         // collect all viewers which define the structure merge viewer extension point
304
elements= registry.getConfigurationElementsFor(PLUGIN_ID, STRUCTURE_MERGE_VIEWER_EXTENSION_POINT);
305         for (int i= 0; i < elements.length; i++) {
306             IConfigurationElement element= elements[i];
307             String JavaDoc name= element.getName();
308             if (!CONTENT_TYPE_BINDING.equals(name)) {
309                 if (!VIEWER_TAG.equals(name))
310                     logErrorMessage(Utilities.getFormattedString("CompareUIPlugin.unexpectedTag", name, VIEWER_TAG)); //$NON-NLS-1$
311
fStructureMergeViewers.register(element, new ViewerDescriptor(element));
312             }
313         }
314         for (int i= 0; i < elements.length; i++) {
315             IConfigurationElement element= elements[i];
316             if (CONTENT_TYPE_BINDING.equals(element.getName()))
317                 fStructureMergeViewers.createBinding(element, STRUCTURE_MERGE_VIEWER_ID_ATTRIBUTE);
318         }
319         
320         // collect all viewers which define the content merge viewer extension point
321
elements= registry.getConfigurationElementsFor(PLUGIN_ID, CONTENT_MERGE_VIEWER_EXTENSION_POINT);
322         for (int i= 0; i < elements.length; i++) {
323             IConfigurationElement element= elements[i];
324             String JavaDoc name= element.getName();
325             if (!CONTENT_TYPE_BINDING.equals(name)) {
326                 if (!VIEWER_TAG.equals(name))
327                     logErrorMessage(Utilities.getFormattedString("CompareUIPlugin.unexpectedTag", name, VIEWER_TAG)); //$NON-NLS-1$
328
fContentMergeViewers.register(element, new ViewerDescriptor(element));
329             }
330         }
331         for (int i= 0; i < elements.length; i++) {
332             IConfigurationElement element= elements[i];
333             if (CONTENT_TYPE_BINDING.equals(element.getName()))
334                 fContentMergeViewers.createBinding(element, CONTENT_MERGE_VIEWER_ID_ATTRIBUTE);
335         }
336         
337         // collect all viewers which define the content viewer extension point
338
elements= registry.getConfigurationElementsFor(PLUGIN_ID, CONTENT_VIEWER_EXTENSION_POINT);
339         for (int i= 0; i < elements.length; i++) {
340             IConfigurationElement element= elements[i];
341             String JavaDoc name= element.getName();
342             if (!CONTENT_TYPE_BINDING.equals(name)) {
343                 if (!VIEWER_TAG.equals(name))
344                     logErrorMessage(Utilities.getFormattedString("CompareUIPlugin.unexpectedTag", name, VIEWER_TAG)); //$NON-NLS-1$
345
fContentViewers.register(element, new ViewerDescriptor(element));
346             }
347         }
348         for (int i= 0; i < elements.length; i++) {
349             IConfigurationElement element= elements[i];
350             if (CONTENT_TYPE_BINDING.equals(element.getName()))
351                 fContentViewers.createBinding(element, CONTENT_VIEWER_ID_ATTRIBUTE);
352         }
353     }
354     
355     public static IWorkbench getActiveWorkbench() {
356         CompareUIPlugin plugin= getDefault();
357         if (plugin == null)
358             return null;
359         return plugin.getWorkbench();
360     }
361     
362     public static IWorkbenchWindow getActiveWorkbenchWindow() {
363         IWorkbench workbench= getActiveWorkbench();
364         if (workbench == null)
365             return null;
366         return workbench.getActiveWorkbenchWindow();
367     }
368     
369     /**
370      * Returns the active workbench page or <code>null</code> if
371      * no active workbench page can be determined.
372      *
373      * @return the active workbench page or <code>null</code> if
374      * no active workbench page can be determined
375      */

376     private static IWorkbenchPage getActivePage() {
377         IWorkbenchWindow window= getActiveWorkbenchWindow();
378         if (window == null)
379             return null;
380         return window.getActivePage();
381     }
382     
383     /**
384      * Returns the SWT Shell of the active workbench window or <code>null</code> if
385      * no workbench window is active.
386      *
387      * @return the SWT Shell of the active workbench window, or <code>null</code> if
388      * no workbench window is active
389      */

390     public static Shell getShell() {
391         IWorkbenchWindow window= getActiveWorkbenchWindow();
392         if (window == null)
393             return null;
394         return window.getShell();
395     }
396
397     /**
398      * Registers the given image for being disposed when this plug-in is shutdown.
399      *
400      * @param image the image to register for disposal
401      */

402     public static void disposeOnShutdown(Image image) {
403         if (image != null)
404             fgDisposeOnShutdownImages.add(image);
405     }
406     
407     /**
408      * Performs the comparison described by the given input and opens a
409      * compare editor on the result.
410      *
411      * @param input the input on which to open the compare editor
412      * @param page the workbench page on which to create a new compare editor
413      * @param editor if not null the input is opened in this editor
414      * @see CompareEditorInput
415      */

416     public void openCompareEditor(final CompareEditorInput input, final IWorkbenchPage page, final IReusableEditor editor) {
417         CompareConfiguration configuration = input.getCompareConfiguration();
418         if (configuration != null) {
419             IPreferenceStore ps= configuration.getPreferenceStore();
420             if (ps != null)
421                 configuration.setProperty(
422                         CompareConfiguration.USE_OUTLINE_VIEW,
423                         Boolean.valueOf(ps.getBoolean(ComparePreferencePage.USE_OUTLINE_VIEW)));
424         }
425         if (input.canRunAsJob()) {
426             openEditorInBackground(input, page, editor);
427         } else {
428             if (compareResultOK(input, null)) {
429                 internalOpenEditor(input, page, editor);
430             }
431         }
432     }
433
434     private void openEditorInBackground(final CompareEditorInput input,
435             final IWorkbenchPage page, final IReusableEditor editor) {
436         internalOpenEditor(input, page, editor);
437     }
438
439     private void internalOpenEditor(final CompareEditorInput input,
440             final IWorkbenchPage wp, final IReusableEditor editor) {
441         Runnable JavaDoc runnable = new Runnable JavaDoc() {
442             public void run() {
443                 if (editor != null && !editor.getSite().getShell().isDisposed()) { // reuse the given editor
444
editor.setInput(input);
445                     return;
446                 }
447                 
448                 IWorkbenchPage page = wp;
449                 if (page == null)
450                     page= getActivePage();
451                 if (page != null) {
452                     // open new CompareEditor on page
453
try {
454                         page.openEditor(input, COMPARE_EDITOR);
455                     } catch (PartInitException e) {
456                         MessageDialog.openError(getShell(), Utilities.getString("CompareUIPlugin.openEditorError"), e.getMessage()); //$NON-NLS-1$
457
}
458                 } else {
459                     MessageDialog.openError(getShell(),
460                             Utilities.getString("CompareUIPlugin.openEditorError"), //$NON-NLS-1$
461
Utilities.getString("CompareUIPlugin.noActiveWorkbenchPage")); //$NON-NLS-1$
462
}
463             }
464         };
465         syncExec(runnable);
466     }
467
468     /**
469      * Performs the comparison described by the given input and opens a
470      * compare dialog on the result.
471      *
472      * @param input the input on which to open the compare editor
473      * @see CompareEditorInput
474      */

475     public void openCompareDialog(final CompareEditorInput input) {
476         // We don't ever open dialogs in the background
477
if (compareResultOK(input, null)) {
478             internalOpenDialog(input);
479         }
480     }
481     
482     public IStatus prepareInput(CompareEditorInput input, IProgressMonitor monitor) {
483         try {
484             input.run(monitor);
485             String JavaDoc message= input.getMessage();
486             if (message != null) {
487                 return new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, message, null);
488             }
489             if (input.getCompareResult() == null) {
490                 return new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, NO_DIFFERENCE, Utilities.getString("CompareUIPlugin.noDifferences"), null); //$NON-NLS-1$
491
}
492             return Status.OK_STATUS;
493         } catch (InterruptedException JavaDoc e) {
494             throw new OperationCanceledException();
495         } catch (InvocationTargetException JavaDoc e) {
496             return new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, Utilities.getString("CompareUIPlugin.compareFailed"), e.getTargetException()); //$NON-NLS-1$
497
}
498     }
499     
500     /*
501      * @return <code>true</code> if compare result is OK to show, <code>false</code> otherwise
502      */

503     public boolean compareResultOK(CompareEditorInput input, IRunnableContext context) {
504         final Shell shell= getShell();
505         try {
506             
507             // run operation in separate thread and make it cancelable
508
if (context == null)
509                 context = PlatformUI.getWorkbench().getProgressService();
510             context.run(true, true, input);
511             
512             String JavaDoc message= input.getMessage();
513             if (message != null) {
514                 MessageDialog.openError(shell, Utilities.getString("CompareUIPlugin.compareFailed"), message); //$NON-NLS-1$
515
return false;
516             }
517             
518             if (input.getCompareResult() == null) {
519                 MessageDialog.openInformation(shell, Utilities.getString("CompareUIPlugin.dialogTitle"), Utilities.getString("CompareUIPlugin.noDifferences")); //$NON-NLS-2$ //$NON-NLS-1$
520
return false;
521             }
522             
523             return true;
524
525         } catch (InterruptedException JavaDoc x) {
526             // canceled by user
527
} catch (InvocationTargetException JavaDoc x) {
528             MessageDialog.openError(shell, Utilities.getString("CompareUIPlugin.compareFailed"), x.getTargetException().getMessage()); //$NON-NLS-1$
529
}
530         return false;
531     }
532         
533     /*
534      * Registers an image for the given type.
535      */

536     private static void registerImage(String JavaDoc type, Image image, boolean dispose) {
537         fgImages.put(normalizeCase(type), image);
538         if (image != null && dispose) {
539             fgDisposeOnShutdownImages.add(image);
540         }
541     }
542     
543     /**
544      * Registers an image descriptor for the given type.
545      *
546      * @param type the type
547      * @param descriptor the image descriptor
548      */

549     public static void registerImageDescriptor(String JavaDoc type, ImageDescriptor descriptor) {
550         fgImageDescriptors.put(normalizeCase(type), descriptor);
551     }
552     
553     public static ImageDescriptor getImageDescriptor(String JavaDoc relativePath) {
554         if (fgComparePlugin == null)
555             return null;
556         IPath path= Utilities.getIconPath(null).append(relativePath);
557         URL JavaDoc url= FileLocator.find(fgComparePlugin.getBundle(), path, null);
558         if (url == null)
559             return null;
560         return ImageDescriptor.createFromURL(url);
561     }
562     
563     /**
564      * Returns a shared image for the given type, or a generic image if none
565      * has been registered for the given type.
566      * <p>
567      * Note: Images returned from this method will be automatically disposed
568      * of when this plug-in shuts down. Callers must not dispose of these
569      * images themselves.
570      * </p>
571      *
572      * @param type the type
573      * @return the image
574      */

575     public static Image getImage(String JavaDoc type) {
576         
577         type= normalizeCase(type);
578         
579         boolean dispose= false;
580         Image image= null;
581         if (type != null)
582             image= (Image) fgImages.get(type);
583         if (image == null) {
584             ImageDescriptor id= (ImageDescriptor) fgImageDescriptors.get(type);
585             if (id != null) {
586                 image= id.createImage();
587                 dispose= true;
588             }
589                 
590             if (image == null) {
591                 if (fgComparePlugin != null) {
592                     if (ITypedElement.FOLDER_TYPE.equals(type)) {
593                         image= getDefault().getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
594                         //image= SharedImages.getImage(ISharedImages.IMG_OBJ_FOLDER);
595
} else {
596                         image= createWorkbenchImage(type);
597                         dispose= true;
598                     }
599                 } else {
600                     id= (ImageDescriptor) fgImageDescriptors.get(normalizeCase("file")); //$NON-NLS-1$
601
image= id.createImage();
602                     dispose= true;
603                 }
604             }
605             if (image != null)
606                 registerImage(type, image, dispose);
607         }
608         return image;
609     }
610     
611     /**
612      * Returns a shared image for the given adaptable.
613      * This convenience method queries the given adaptable
614      * for its <code>IWorkbenchAdapter.getImageDescriptor</code>, which it
615      * uses to create an image if it does not already have one.
616      * <p>
617      * Note: Images returned from this method will be automatically disposed
618      * of when this plug-in shuts down. Callers must not dispose of these
619      * images themselves.
620      * </p>
621      *
622      * @param adaptable the adaptable for which to find an image
623      * @return an image
624      */

625     public static Image getImage(IAdaptable adaptable) {
626         if (adaptable != null) {
627             Object JavaDoc o= adaptable.getAdapter(IWorkbenchAdapter.class);
628             if (o instanceof IWorkbenchAdapter) {
629                 ImageDescriptor id= ((IWorkbenchAdapter) o).getImageDescriptor(adaptable);
630                 if (id != null) {
631                     Image image= (Image)fgImages2.get(id);
632                     if (image == null) {
633                         image= id.createImage();
634                         try {
635                             fgImages2.put(id, image);
636                         } catch (NullPointerException JavaDoc ex) {
637                             // NeedWork
638
}
639                         fgDisposeOnShutdownImages.add(image);
640
641                     }
642                     return image;
643                 }
644             }
645         }
646         return null;
647     }
648     
649     private static Image createWorkbenchImage(String JavaDoc type) {
650         IEditorRegistry er= getDefault().getWorkbench().getEditorRegistry();
651         ImageDescriptor id= er.getImageDescriptor("foo." + type); //$NON-NLS-1$
652
return id.createImage();
653     }
654     
655     /**
656      * Returns an structure creator descriptor for the given type.
657      *
658      * @param type the type for which to find a descriptor
659      * @return a descriptor for the given type, or <code>null</code> if no
660      * descriptor has been registered
661      */

662     public StructureCreatorDescriptor getStructureCreator(String JavaDoc type) {
663         initializeRegistries();
664         return (StructureCreatorDescriptor) fStructureCreators.search(type);
665     }
666     
667     /**
668      * Returns a stream merger for the given type.
669      *
670      * @param type the type for which to find a stream merger
671      * @return a stream merger for the given type, or <code>null</code> if no
672      * stream merger has been registered
673      */

674     public IStreamMerger createStreamMerger(String JavaDoc type) {
675         initializeRegistries();
676         StreamMergerDescriptor descriptor= (StreamMergerDescriptor) fStreamMergers.search(type);
677         if (descriptor != null)
678             return descriptor.createStreamMerger();
679         return null;
680     }
681     
682     /**
683      * Returns a stream merger for the given content type.
684      *
685      * @param type the type for which to find a stream merger
686      * @return a stream merger for the given type, or <code>null</code> if no
687      * stream merger has been registered
688      */

689     public IStreamMerger createStreamMerger(IContentType type) {
690         initializeRegistries();
691         StreamMergerDescriptor descriptor= (StreamMergerDescriptor) fStreamMergers.search(type);
692         if (descriptor != null)
693             return descriptor.createStreamMerger();
694         return null;
695     }
696     
697     /**
698      * Returns a structure compare viewer based on an old viewer and an input object.
699      * If the old viewer is suitable for showing the input, the old viewer
700      * is returned. Otherwise, the input's type is used to find a viewer descriptor in the registry
701      * which in turn is used to create a structure compare viewer under the given parent composite.
702      * If no viewer descriptor can be found <code>null</code> is returned.
703      *
704      * @param oldViewer a new viewer is only created if this old viewer cannot show the given input
705      * @param input the input object for which to find a structure viewer
706      * @param parent the SWT parent composite under which the new viewer is created
707      * @param configuration a configuration which is passed to a newly created viewer
708      * @return the compare viewer which is suitable for the given input object or <code>null</code>
709      */

710     public Viewer findStructureViewer(Viewer oldViewer, ICompareInput input, Composite parent,
711                 CompareConfiguration configuration) {
712
713         if (input.getLeft() == null || input.getRight() == null) // we don't show the structure of additions or deletions
714
return null;
715                     
716         // content type search
717
IContentType ctype= getCommonType(input);
718         if (ctype != null) {
719             initializeRegistries();
720             Viewer viewer= getViewer(fStructureMergeViewers.search(ctype), oldViewer, parent, configuration);
721             if (viewer != null)
722                 return viewer;
723         }
724         
725         // old style search
726
String JavaDoc[] types= getTypes(input);
727         String JavaDoc type= null;
728         if (isHomogenous(types)) {
729             type= normalizeCase(types[0]);
730             initializeRegistries();
731             IViewerDescriptor vd= (IViewerDescriptor) fStructureMergeViewers.search(type);
732             if (vd == null) {
733                 String JavaDoc alias= getStructureViewerAlias(type);
734                 if (alias != null)
735                     vd= (IViewerDescriptor) fStructureMergeViewers.search(alias);
736             }
737             if (vd != null)
738                 return vd.createViewer(oldViewer, parent, configuration);
739         }
740         
741         // we didn't found any viewer so far.
742
// now we try to find a structure creator for the generic StructureDiffViewer
743

744         StructureCreatorDescriptor scc= null;
745         initializeRegistries();
746         Object JavaDoc desc= fStructureCreators.search(ctype); // search for content type
747
if (desc instanceof StructureCreatorDescriptor)
748             scc= (StructureCreatorDescriptor) desc;
749         if (scc == null && type != null)
750             scc= getStructureCreator(type); // search for old-style type scheme
751
if (scc != null) {
752             IStructureCreator sc= scc.createStructureCreator();
753             if (sc != null) {
754                 StructureDiffViewer sdv= new StructureDiffViewer(parent, configuration);
755                 sdv.setStructureCreator(sc);
756                 return sdv;
757             }
758         }
759         return null;
760     }
761     
762     /**
763      * Returns a content compare viewer based on an old viewer and an input object.
764      * If the old viewer is suitable for showing the input the old viewer
765      * is returned. Otherwise the input's type is used to find a viewer descriptor in the registry
766      * which in turn is used to create a content compare viewer under the given parent composite.
767      * If no viewer descriptor can be found <code>null</code> is returned.
768      *
769      * @param oldViewer a new viewer is only created if this old viewer cannot show the given input
770      * @param in the input object for which to find a content viewer
771      * @param parent the SWT parent composite under which the new viewer is created
772      * @param cc a configuration which is passed to a newly created viewer
773      * @return the compare viewer which is suitable for the given input object or <code>null</code>
774      */

775     public Viewer findContentViewer(Viewer oldViewer, Object JavaDoc in, Composite parent, CompareConfiguration cc) {
776         
777         if (in instanceof IStreamContentAccessor) {
778             String JavaDoc type= ITypedElement.TEXT_TYPE;
779             
780             if (in instanceof ITypedElement) {
781                 ITypedElement tin= (ITypedElement) in;
782                             
783                 IContentType ct= getContentType(tin);
784                 if (ct != null) {
785                     initializeRegistries();
786                     Viewer viewer= getViewer(fContentViewers.search(ct), oldViewer, parent, cc);
787                     if (viewer != null)
788                         return viewer;
789                 }
790                 
791                 String JavaDoc ty= tin.getType();
792                 if (ty != null)
793                     type= ty;
794             }
795             
796             initializeRegistries();
797             Viewer viewer= getViewer(fContentViewers.search(type), oldViewer, parent, cc);
798             if (viewer != null)
799                 return viewer;
800             // fallback
801
return new SimpleTextViewer(parent);
802         }
803
804         if (!(in instanceof ICompareInput))
805             return null;
806             
807         ICompareInput input= (ICompareInput) in;
808
809         
810         IContentType ctype= getCommonType(input);
811         if (isCompareAsText(input, cc)) {
812             ctype = Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT);
813         }
814         if (ctype != null) {
815             initializeRegistries();
816             Viewer viewer= getViewer(fContentMergeViewers.search(ctype), oldViewer, parent, cc);
817             if (viewer != null)
818                 return viewer;
819         }
820         
821         String JavaDoc[] types= getTypes(input);
822         String JavaDoc type= null;
823         if (isHomogenous(types))
824             type= types[0];
825         
826         if (ITypedElement.FOLDER_TYPE.equals(type))
827             return null;
828             
829         if (type == null) {
830             int n= 0;
831             for (int i= 0; i < types.length; i++)
832                 if (!ITypedElement.UNKNOWN_TYPE.equals(types[i])) {
833                     n++;
834                     if (type == null)
835                         type= types[i]; // remember the first known type
836
}
837             if (n > 1) // don't use the type if there were more than one
838
type= null;
839         }
840         
841         if (type != null) {
842             initializeRegistries();
843             Viewer viewer= getViewer(fContentMergeViewers.search(type), oldViewer, parent, cc);
844             if (viewer != null)
845                 return viewer;
846         }
847
848         // fallback
849
String JavaDoc leftType= guessType(input.getLeft());
850         String JavaDoc rightType= guessType(input.getRight());
851             
852         if (leftType != null || rightType != null) {
853             boolean right_text= rightType != null && ITypedElement.TEXT_TYPE.equals(rightType);
854             boolean left_text= leftType != null && ITypedElement.TEXT_TYPE.equals(leftType);
855             if ((leftType == null && right_text) || (left_text && rightType == null) || (left_text && right_text))
856                 type= ITypedElement.TEXT_TYPE;
857             else
858                 type= BINARY_TYPE;
859             
860             initializeRegistries();
861             IViewerDescriptor vd= (IViewerDescriptor) fContentMergeViewers.search(type);
862             if (vd != null)
863                 return vd.createViewer(oldViewer, parent, cc);
864         }
865         return null;
866     }
867     
868     private boolean isCompareAsText(ICompareInput input, CompareConfiguration cc) {
869         Set set = (Set)cc.getProperty(ICompareAsText.PROP_TEXT_INPUTS);
870         if (set == null)
871             return false;
872         return set.contains(input);
873     }
874
875     private static Viewer getViewer(Object JavaDoc descriptor, Viewer oldViewer, Composite parent, CompareConfiguration cc) {
876         if (descriptor instanceof IViewerDescriptor)
877             return ((IViewerDescriptor)descriptor).createViewer(oldViewer, parent, cc);
878         return null;
879     }
880     
881     private static String JavaDoc[] getTypes(ICompareInput input) {
882         ITypedElement ancestor= input.getAncestor();
883         ITypedElement left= input.getLeft();
884         ITypedElement right= input.getRight();
885         
886         ArrayList tmp= new ArrayList();
887         if (ancestor != null) {
888             String JavaDoc type= ancestor.getType();
889             if (type != null)
890                 tmp.add(normalizeCase(type));
891         }
892         if (left != null) {
893             String JavaDoc type= left.getType();
894             if (type != null)
895                 tmp.add(normalizeCase(type));
896         }
897         if (right != null) {
898             String JavaDoc type= right.getType();
899             if (type != null)
900                 tmp.add(normalizeCase(type));
901         }
902         return (String JavaDoc[]) tmp.toArray(new String JavaDoc[tmp.size()]);
903     }
904         
905     private static IContentType getContentType(ITypedElement element) {
906         if (element == null)
907             return null;
908         String JavaDoc name= element.getName();
909         IContentType ct= null;
910         if (element instanceof IStreamContentAccessor) {
911             IStreamContentAccessor isa= (IStreamContentAccessor) element;
912             try {
913                 InputStream is= isa.getContents();
914                 if (is != null) {
915                     InputStream bis= new BufferedInputStream(is);
916                     try {
917                         ct= fgContentTypeManager.findContentTypeFor(is, name);
918                     } catch (IOException e) {
919                         // silently ignored
920
} finally {
921                         try {
922                             bis.close();
923                         } catch (IOException e2) {
924                             // silently ignored
925
}
926                     }
927                 }
928             } catch (CoreException e1) {
929                 // silently ignored
930
}
931         }
932         if (ct == null)
933             ct= fgContentTypeManager.findContentTypeFor(name);
934         return ct;
935     }
936     
937     /*
938      * Returns true if the given types are homogeneous.
939      */

940     private static boolean isHomogenous(String JavaDoc[] types) {
941         switch (types.length) {
942         case 1:
943             return true;
944         case 2:
945             return types[0].equals(types[1]);
946         case 3:
947             return types[0].equals(types[1]) && types[1].equals(types[2]);
948         }
949         return false;
950     }
951     
952     /*
953      * Returns the most specific content type that is common to the given inputs or null.
954      */

955     private static IContentType getCommonType(ICompareInput input) {
956
957         ITypedElement ancestor= input.getAncestor();
958         ITypedElement left= input.getLeft();
959         ITypedElement right= input.getRight();
960         
961         int n= 0;
962         IContentType[] types= new IContentType[3];
963         IContentType type= null;
964         
965         if (ancestor != null) {
966             type= getContentType(ancestor);
967             if (type != null)
968                 types[n++]= type;
969         }
970         type= getContentType(left);
971         if (type != null)
972             types[n++]= type;
973         else
974             return null;
975         type= getContentType(right);
976         if (type != null)
977             types[n++]= type;
978         else
979             return null;
980                 
981         IContentType result= null;
982         IContentType[] s0, s1, s2;
983             switch (n) {
984             case 0:
985                 return null;
986         case 1:
987             return types[0];
988         case 2:
989             if (types[0].equals(types[1]))
990                 return types[0];
991             s0= toFullPath(types[0]);
992             s1= toFullPath(types[1]);
993             for (int i= 0; i < Math.min(s0.length, s1.length); i++) {
994                 if (!s0[i].equals(s1[i]))
995                     break;
996                 result= s0[i];
997             }
998             return result;
999         case 3:
1000            if (types[0].equals(types[1]) && types[1].equals(types[2]))
1001                return types[0];
1002            s0= toFullPath(types[0]);
1003            s1= toFullPath(types[1]);
1004            s2= toFullPath(types[2]);
1005            for (int i= 0; i < Math.min(Math.min(s0.length, s1.length), s2.length); i++) {
1006                if (!s0[i].equals(s1[i]) || !s1[i].equals(s2[i]))
1007                    break;
1008                result= s0[i];
1009            }
1010            return result;
1011        }
1012        return null;
1013    }
1014    
1015    private static IContentType[] toFullPath(IContentType ct) {
1016        List JavaDoc l= new ArrayList();
1017        for (; ct != null; ct= ct.getBaseType())
1018            l.add(0, ct);
1019        return (IContentType[]) l.toArray(new IContentType[l.size()]);
1020    }
1021        
1022    /*
1023     * Guesses the file type of the given input.
1024     * Returns ITypedElement.TEXT_TYPE if none of the first 10 lines is longer than 1000 bytes.
1025     * Returns ITypedElement.UNKNOWN_TYPE otherwise.
1026     * Returns <code>null</code> if the input isn't an <code>IStreamContentAccessor</code>.
1027     */

1028    private static String JavaDoc guessType(ITypedElement input) {
1029        if (input instanceof IStreamContentAccessor) {
1030            IStreamContentAccessor sca= (IStreamContentAccessor) input;
1031            InputStream is= null;
1032            try {
1033                is= sca.getContents();
1034                if (is == null)
1035                    return null;
1036                int lineLength= 0;
1037                int lines= 0;
1038                while (lines < 10) {
1039                    int c= is.read();
1040                    if (c == -1) // EOF
1041
break;
1042                    if (c == '\n' || c == '\r') { // reset line length
1043
lineLength= 0;
1044                        lines++;
1045                    } else
1046                        lineLength++;
1047                    if (lineLength > 1000)
1048                        return ITypedElement.UNKNOWN_TYPE;
1049                }
1050                return ITypedElement.TEXT_TYPE;
1051            } catch (CoreException ex) {
1052                // be silent and return UNKNOWN_TYPE
1053
} catch (IOException ex) {
1054                // be silent and return UNKNOWN_TYPE
1055
} finally {
1056                if (is != null) {
1057                    try {
1058                        is.close();
1059                    } catch (IOException ex) {
1060                        // silently ignored
1061
}
1062                }
1063            }
1064            return ITypedElement.UNKNOWN_TYPE;
1065        }
1066        return null;
1067    }
1068    
1069    private static String JavaDoc normalizeCase(String JavaDoc s) {
1070        if (NORMALIZE_CASE && s != null)
1071            return s.toUpperCase();
1072        return s;
1073    }
1074    
1075    //---- alias management
1076

1077    private String JavaDoc getStructureViewerAlias(String JavaDoc type) {
1078        return (String JavaDoc) getStructureViewerAliases().get(type);
1079    }
1080
1081    public void addStructureViewerAlias(String JavaDoc type, String JavaDoc alias) {
1082        getStructureViewerAliases().put(normalizeCase(alias), normalizeCase(type));
1083    }
1084    
1085    private Map getStructureViewerAliases() {
1086        if (fStructureViewerAliases == null) {
1087            fStructureViewerAliases= new Hashtable(10);
1088            String JavaDoc aliases= getPreferenceStore().getString(STRUCTUREVIEWER_ALIASES_PREFERENCE_NAME);
1089            if (aliases != null && aliases.length() > 0) {
1090                StringTokenizer st= new StringTokenizer(aliases, " "); //$NON-NLS-1$
1091
while (st.hasMoreTokens()) {
1092                    String JavaDoc pair= st.nextToken();
1093                    int pos= pair.indexOf('.');
1094                    if (pos > 0) {
1095                        String JavaDoc key= pair.substring(0, pos);
1096                        String JavaDoc alias= pair.substring(pos+1);
1097                        fStructureViewerAliases.put(key, alias);
1098                    }
1099                }
1100            }
1101        }
1102        return fStructureViewerAliases;
1103    }
1104    
1105    public void removeAllStructureViewerAliases(String JavaDoc type) {
1106        if (fStructureViewerAliases == null)
1107            return;
1108        String JavaDoc t= normalizeCase(type);
1109        Set entrySet= fStructureViewerAliases.entrySet();
1110        for (Iterator iter= entrySet.iterator(); iter.hasNext(); ) {
1111            Map.Entry entry= (Map.Entry)iter.next();
1112            if (entry.getValue().equals(t))
1113                iter.remove();
1114        }
1115    }
1116    
1117    /*
1118     * Converts the aliases into a single string before they are stored
1119     * in the preference store.
1120     * The format is:
1121     * <key> '.' <alias> ' ' <key> '.' <alias> ...
1122     */

1123    private void rememberAliases(IPreferenceStore ps) {
1124        if (fStructureViewerAliases == null)
1125            return;
1126        StringBuffer JavaDoc buffer= new StringBuffer JavaDoc();
1127        Iterator iter= fStructureViewerAliases.keySet().iterator();
1128        while (iter.hasNext()) {
1129            String JavaDoc key= (String JavaDoc) iter.next();
1130            String JavaDoc alias= (String JavaDoc) fStructureViewerAliases.get(key);
1131            buffer.append(key);
1132            buffer.append('.');
1133            buffer.append(alias);
1134            buffer.append(' ');
1135        }
1136        ps.setValue(STRUCTUREVIEWER_ALIASES_PREFERENCE_NAME, buffer.toString());
1137    }
1138
1139    //---- filters
1140

1141    public boolean filter(String JavaDoc name, boolean isFolder, boolean isArchive) {
1142        if (fFilter == null) {
1143            fFilter= new CompareFilter();
1144            final IPreferenceStore ps= getPreferenceStore();
1145            fFilter.setFilters(ps.getString(ComparePreferencePage.PATH_FILTER));
1146            fPropertyChangeListener= new IPropertyChangeListener() {
1147                public void propertyChange(PropertyChangeEvent event) {
1148                    if (ComparePreferencePage.PATH_FILTER.equals(event.getProperty()))
1149                        fFilter.setFilters(ps.getString(ComparePreferencePage.PATH_FILTER));
1150                }
1151            };
1152            ps.addPropertyChangeListener(fPropertyChangeListener);
1153        }
1154        return fFilter.filter(name, isFolder, isArchive);
1155    }
1156    
1157    private void internalOpenDialog(final CompareEditorInput input) {
1158        Runnable JavaDoc runnable = new Runnable JavaDoc() {
1159            public void run() {
1160                CompareDialog dialog= new CompareDialog(getShell(), input);
1161                dialog.open();
1162            }
1163        };
1164        syncExec(runnable);
1165    }
1166
1167    private void syncExec(Runnable JavaDoc runnable) {
1168        if (Display.getCurrent() == null) {
1169            Display.getDefault().syncExec(runnable);
1170        } else {
1171            runnable.run();
1172        }
1173    }
1174
1175    //---- more utilities
1176

1177    protected void handleNoDifference() {
1178        Runnable JavaDoc runnable = new Runnable JavaDoc() {
1179            public void run() {
1180                MessageDialog.openInformation(getShell(), Utilities.getString("CompareUIPlugin.dialogTitle"), Utilities.getString("CompareUIPlugin.noDifferences")); //$NON-NLS-1$//$NON-NLS-2$
1181
}
1182        };
1183        syncExec(runnable);
1184    }
1185
1186    /**
1187     * Returns an array of all editors that have an unsaved content. If the identical content is
1188     * presented in more than one editor, only one of those editor parts is part of the result.
1189     *
1190     * @return an array of all dirty editor parts.
1191     */

1192    public static IEditorPart[] getDirtyEditors() {
1193        Set inputs= new HashSet();
1194        List JavaDoc result= new ArrayList(0);
1195        IWorkbench workbench= getDefault().getWorkbench();
1196        IWorkbenchWindow[] windows= workbench.getWorkbenchWindows();
1197        for (int i= 0; i < windows.length; i++) {
1198            IWorkbenchPage[] pages= windows[i].getPages();
1199            for (int x= 0; x < pages.length; x++) {
1200                IEditorPart[] editors= pages[x].getDirtyEditors();
1201                for (int z= 0; z < editors.length; z++) {
1202                    IEditorPart ep= editors[z];
1203                    IEditorInput input= ep.getEditorInput();
1204                    if (!inputs.contains(input)) {
1205                        inputs.add(input);
1206                        result.add(ep);
1207                    }
1208                }
1209            }
1210        }
1211        return (IEditorPart[])result.toArray(new IEditorPart[result.size()]);
1212    }
1213        
1214    public static void logErrorMessage(String JavaDoc message) {
1215        if (message == null)
1216            message= ""; //$NON-NLS-1$
1217
log(new Status(IStatus.ERROR, getPluginId(), INTERNAL_ERROR, message, null));
1218    }
1219
1220    public static void log(Throwable JavaDoc e) {
1221        log(new Status(IStatus.ERROR, getPluginId(), INTERNAL_ERROR, CompareMessages.ComparePlugin_internal_error, e));
1222    }
1223    
1224    public static void log(IStatus status) {
1225        getDefault().getLog().log(status);
1226    }
1227
1228    public boolean isUseOldDifferencer() {
1229        return useOldDifferencer;
1230    }
1231
1232    public void setUseOldDifferencer(boolean useOldDifferencer) {
1233        this.useOldDifferencer = useOldDifferencer;
1234    }
1235}
1236
Popular Tags