KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > actions > OpenWithMenu


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  * Benjamin Muskalla - Bug 29633 [EditorMgmt] "Open" menu should
11  * have Open With-->Other
12  *******************************************************************************/

13 package org.eclipse.ui.actions;
14
15 import java.util.ArrayList JavaDoc;
16 import java.util.Arrays JavaDoc;
17 import java.util.Collections JavaDoc;
18 import java.util.Comparator JavaDoc;
19 import java.util.Hashtable JavaDoc;
20
21 import org.eclipse.core.resources.IFile;
22 import org.eclipse.core.resources.IResource;
23 import org.eclipse.core.runtime.IAdaptable;
24 import org.eclipse.jface.action.ContributionItem;
25 import org.eclipse.jface.resource.ImageDescriptor;
26 import org.eclipse.jface.window.Window;
27 import org.eclipse.osgi.util.NLS;
28 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.graphics.Image;
30 import org.eclipse.swt.widgets.Event;
31 import org.eclipse.swt.widgets.Listener;
32 import org.eclipse.swt.widgets.Menu;
33 import org.eclipse.swt.widgets.MenuItem;
34 import org.eclipse.ui.IEditorDescriptor;
35 import org.eclipse.ui.IEditorRegistry;
36 import org.eclipse.ui.IWorkbenchPage;
37 import org.eclipse.ui.PartInitException;
38 import org.eclipse.ui.PlatformUI;
39 import org.eclipse.ui.dialogs.EditorSelectionDialog;
40 import org.eclipse.ui.ide.IDE;
41 import org.eclipse.ui.internal.WorkbenchPage;
42 import org.eclipse.ui.internal.ide.DialogUtil;
43 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
44 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
45 import org.eclipse.ui.part.FileEditorInput;
46
47 import com.ibm.icu.text.Collator;
48
49 /**
50  * A menu for opening files in the workbench.
51  * <p>
52  * An <code>OpenWithMenu</code> is used to populate a menu with
53  * "Open With" actions. One action is added for each editor which is applicable
54  * to the selected file. If the user selects one of these items, the corresponding
55  * editor is opened on the file.
56  * </p>
57  * <p>
58  * This class may be instantiated; it is not intended to be subclassed.
59  * </p>
60  */

61 public class OpenWithMenu extends ContributionItem {
62     private IWorkbenchPage page;
63
64     private IAdaptable file;
65
66     private IEditorRegistry registry = PlatformUI.getWorkbench()
67             .getEditorRegistry();
68
69     private static Hashtable JavaDoc imageCache = new Hashtable JavaDoc(11);
70
71     /**
72      * The id of this action.
73      */

74     public static final String JavaDoc ID = PlatformUI.PLUGIN_ID + ".OpenWithMenu";//$NON-NLS-1$
75

76     /**
77      * Match both the input and id, so that different types of editor can be opened on the same input.
78      */

79     private static final int MATCH_BOTH = IWorkbenchPage.MATCH_INPUT | IWorkbenchPage.MATCH_ID;
80     
81     /*
82      * Compares the labels from two IEditorDescriptor objects
83      */

84     private static final Comparator JavaDoc comparer = new Comparator JavaDoc() {
85         private Collator collator = Collator.getInstance();
86
87         public int compare(Object JavaDoc arg0, Object JavaDoc arg1) {
88             String JavaDoc s1 = ((IEditorDescriptor) arg0).getLabel();
89             String JavaDoc s2 = ((IEditorDescriptor) arg1).getLabel();
90             return collator.compare(s1, s2);
91         }
92     };
93
94     /**
95      * Constructs a new instance of <code>OpenWithMenu</code>.
96      * <p>
97      * If this method is used be sure to set the selected file by invoking
98      * <code>setFile</code>. The file input is required when the user
99      * selects an item in the menu. At that point the menu will attempt to
100      * open an editor with the file as its input.
101      * </p>
102      *
103      * @param page the page where the editor is opened if an item within
104      * the menu is selected
105      */

106     public OpenWithMenu(IWorkbenchPage page) {
107         this(page, null);
108     }
109
110     /**
111      * Constructs a new instance of <code>OpenWithMenu</code>.
112      *
113      * @param page the page where the editor is opened if an item within
114      * the menu is selected
115      * @param file the selected file
116      */

117     public OpenWithMenu(IWorkbenchPage page, IAdaptable file) {
118         super(ID);
119         this.page = page;
120         this.file = file;
121     }
122
123     /**
124      * Returns an image to show for the corresponding editor descriptor.
125      *
126      * @param editorDesc the editor descriptor, or null for the system editor
127      * @return the image or null
128      */

129     private Image getImage(IEditorDescriptor editorDesc) {
130         ImageDescriptor imageDesc = getImageDescriptor(editorDesc);
131         if (imageDesc == null) {
132             return null;
133         }
134         Image image = (Image) imageCache.get(imageDesc);
135         if (image == null) {
136             image = imageDesc.createImage();
137             imageCache.put(imageDesc, image);
138         }
139         return image;
140     }
141
142     /**
143      * Returns the image descriptor for the given editor descriptor,
144      * or null if it has no image.
145      */

146     private ImageDescriptor getImageDescriptor(IEditorDescriptor editorDesc) {
147         ImageDescriptor imageDesc = null;
148         if (editorDesc == null) {
149             imageDesc = registry
150                     .getImageDescriptor(getFileResource().getName());
151             //TODO: is this case valid, and if so, what are the implications for content-type editor bindings?
152
} else {
153             imageDesc = editorDesc.getImageDescriptor();
154         }
155         if (imageDesc == null) {
156             if (editorDesc.getId().equals(
157                     IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID)) {
158                 imageDesc = registry
159                         .getSystemExternalEditorImageDescriptor(getFileResource()
160                                 .getName());
161             }
162         }
163         return imageDesc;
164     }
165
166     /**
167      * Creates the menu item for the editor descriptor.
168      *
169      * @param menu the menu to add the item to
170      * @param descriptor the editor descriptor, or null for the system editor
171      * @param preferredEditor the descriptor of the preferred editor, or <code>null</code>
172      */

173     private void createMenuItem(Menu menu, final IEditorDescriptor descriptor,
174             final IEditorDescriptor preferredEditor) {
175         // XXX: Would be better to use bold here, but SWT does not support it.
176
final MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
177         boolean isPreferred = preferredEditor != null
178                 && descriptor.getId().equals(preferredEditor.getId());
179         menuItem.setSelection(isPreferred);
180         menuItem.setText(descriptor.getLabel());
181         Image image = getImage(descriptor);
182         if (image != null) {
183             menuItem.setImage(image);
184         }
185         Listener listener = new Listener() {
186             public void handleEvent(Event event) {
187                 switch (event.type) {
188                 case SWT.Selection:
189                     if (menuItem.getSelection()) {
190                         openEditor(descriptor, false);
191                     }
192                     break;
193                 }
194             }
195         };
196         menuItem.addListener(SWT.Selection, listener);
197     }
198
199     /**
200      * Creates the Other... menu item
201      *
202      * @param menu the menu to add the item to
203      */

204     private void createOtherMenuItem(final Menu menu) {
205         final IFile fileResource = getFileResource();
206         if (fileResource == null) {
207             return;
208         }
209         new MenuItem(menu, SWT.SEPARATOR);
210         final MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
211         menuItem.setText(IDEWorkbenchMessages.OpenWithMenu_Other);
212         Listener listener = new Listener() {
213             public void handleEvent(Event event) {
214                 switch (event.type) {
215                 case SWT.Selection:
216                     EditorSelectionDialog dialog = new EditorSelectionDialog(
217                             menu.getShell());
218                     dialog
219                             .setMessage(NLS
220                                     .bind(
221                                             IDEWorkbenchMessages.OpenWithMenu_OtherDialogDescription,
222                                             fileResource.getName()));
223                     if (dialog.open() == Window.OK) {
224                         IEditorDescriptor editor = dialog.getSelectedEditor();
225                         if (editor != null) {
226                             openEditor(editor, editor.isOpenExternal());
227                         }
228                     }
229                     break;
230                 }
231             }
232         };
233         menuItem.addListener(SWT.Selection, listener);
234     }
235     
236     /* (non-Javadoc)
237      * Fills the menu with perspective items.
238      */

239     public void fill(Menu menu, int index) {
240         IFile file = getFileResource();
241         if (file == null) {
242             return;
243         }
244
245         IEditorDescriptor defaultEditor = registry
246                 .findEditor(IDEWorkbenchPlugin.DEFAULT_TEXT_EDITOR_ID); // may be null
247
IEditorDescriptor preferredEditor = IDE.getDefaultEditor(file); // may be null
248

249         Object JavaDoc[] editors = registry.getEditors(file.getName(), IDE.getContentType(file));
250         Collections.sort(Arrays.asList(editors), comparer);
251
252         boolean defaultFound = false;
253
254         //Check that we don't add it twice. This is possible
255
//if the same editor goes to two mappings.
256
ArrayList JavaDoc alreadyMapped = new ArrayList JavaDoc();
257
258         for (int i = 0; i < editors.length; i++) {
259             IEditorDescriptor editor = (IEditorDescriptor) editors[i];
260             if (!alreadyMapped.contains(editor)) {
261                 createMenuItem(menu, editor, preferredEditor);
262                 if (defaultEditor != null
263                         && editor.getId().equals(defaultEditor.getId())) {
264                     defaultFound = true;
265                 }
266                 alreadyMapped.add(editor);
267             }
268         }
269
270         // Only add a separator if there is something to separate
271
if (editors.length > 0) {
272             new MenuItem(menu, SWT.SEPARATOR);
273         }
274
275         // Add default editor. Check it if it is saved as the preference.
276
if (!defaultFound && defaultEditor != null) {
277             createMenuItem(menu, defaultEditor, preferredEditor);
278         }
279
280         // Add system editor (should never be null)
281
IEditorDescriptor descriptor = registry
282                 .findEditor(IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);
283         createMenuItem(menu, descriptor, preferredEditor);
284
285         // Add system in-place editor (can be null)
286
descriptor = registry
287                 .findEditor(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID);
288         if (descriptor != null) {
289             createMenuItem(menu, descriptor, preferredEditor);
290         }
291         createDefaultMenuItem(menu, file);
292         
293         // add Other... menu item
294
createOtherMenuItem(menu);
295     }
296     
297
298     /**
299      * Converts the IAdaptable file to IFile or null.
300      */

301     private IFile getFileResource() {
302         if (this.file instanceof IFile) {
303             return (IFile) this.file;
304         }
305         IResource resource = (IResource) this.file
306                 .getAdapter(IResource.class);
307         if (resource instanceof IFile) {
308             return (IFile) resource;
309         }
310        
311         return null;
312     }
313
314     /* (non-Javadoc)
315      * Returns whether this menu is dynamic.
316      */

317     public boolean isDynamic() {
318         return true;
319     }
320
321     /**
322      * Opens the given editor on the selected file.
323      *
324      * @param editor the editor descriptor, or null for the system editor
325      * @param openUsingDescriptor use the descriptor's editor ID for opening if false (normal case),
326      * or use the descriptor itself if true (needed to fix bug 178235).
327      */

328     private void openEditor(IEditorDescriptor editor, boolean openUsingDescriptor) {
329         IFile file = getFileResource();
330         if (file == null) {
331             return;
332         }
333         try {
334             if (openUsingDescriptor) {
335                 ((WorkbenchPage) page).openEditorFromDescriptor(new FileEditorInput(file), editor, true, null);
336             } else {
337                 String JavaDoc editorId = editor == null ? IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID
338                         : editor.getId();
339                 
340                 ((WorkbenchPage) page).openEditor(new FileEditorInput(file), editorId, true, MATCH_BOTH);
341                 // only remember the default editor if the open succeeds
342
IDE.setDefaultEditor(file, editorId);
343             }
344         } catch (PartInitException e) {
345             DialogUtil.openError(page.getWorkbenchWindow().getShell(),
346                     IDEWorkbenchMessages.OpenWithMenu_dialogTitle,
347                     e.getMessage(), e);
348         }
349     }
350
351     /**
352      * Creates the menu item for clearing the current selection.
353      *
354      * @param menu the menu to add the item to
355      * @param file the file being edited
356      */

357     private void createDefaultMenuItem(Menu menu, final IFile file) {
358         final MenuItem menuItem = new MenuItem(menu, SWT.RADIO);
359         menuItem.setSelection(IDE.getDefaultEditor(file) == null);
360         menuItem.setText(IDEWorkbenchMessages.DefaultEditorDescription_name);
361
362         Listener listener = new Listener() {
363             public void handleEvent(Event event) {
364                 switch (event.type) {
365                 case SWT.Selection:
366                     if (menuItem.getSelection()) {
367                         IDE.setDefaultEditor(file, null);
368                         try {
369                             IEditorDescriptor desc = IDE.getEditorDescriptor(file);
370                             page.openEditor(new FileEditorInput(file), desc.getId(), true, MATCH_BOTH);
371                         } catch (PartInitException e) {
372                             DialogUtil.openError(page.getWorkbenchWindow()
373                                     .getShell(), IDEWorkbenchMessages.OpenWithMenu_dialogTitle,
374                                     e.getMessage(), e);
375                         }
376                     }
377                     break;
378                 }
379             }
380         };
381
382         menuItem.addListener(SWT.Selection, listener);
383     }
384 }
385
Popular Tags