Better default editor opening for file revisions
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / EgitUiEditorUtils.java
blob4fe691112547caea04586730448e131919f2e87c
1 /*******************************************************************************
2 * Copyright (c) 2000, 2016 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 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
8 * SPDX-License-Identifier: EPL-2.0
10 * Contributors:
11 * IBM Corporation - initial API and implementation
12 *******************************************************************************/
13 package org.eclipse.egit.ui.internal;
15 import java.io.File;
16 import java.io.IOException;
17 import java.io.InputStream;
19 import org.eclipse.core.filesystem.EFS;
20 import org.eclipse.core.filesystem.IFileStore;
21 import org.eclipse.core.resources.IFile;
22 import org.eclipse.core.resources.IStorage;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IPath;
25 import org.eclipse.core.runtime.IProgressMonitor;
26 import org.eclipse.core.runtime.Path;
27 import org.eclipse.core.runtime.Platform;
28 import org.eclipse.core.runtime.SubMonitor;
29 import org.eclipse.core.runtime.content.IContentType;
30 import org.eclipse.egit.core.internal.util.ResourceUtil;
31 import org.eclipse.egit.ui.Activator;
32 import org.eclipse.egit.ui.internal.revision.FileRevisionEditorInput;
33 import org.eclipse.jface.text.BadLocationException;
34 import org.eclipse.jface.text.IDocument;
35 import org.eclipse.jface.util.OpenStrategy;
36 import org.eclipse.jgit.annotations.Nullable;
37 import org.eclipse.osgi.util.NLS;
38 import org.eclipse.team.core.history.IFileRevision;
39 import org.eclipse.ui.IEditorDescriptor;
40 import org.eclipse.ui.IEditorPart;
41 import org.eclipse.ui.IEditorRegistry;
42 import org.eclipse.ui.IWorkbenchPage;
43 import org.eclipse.ui.PartInitException;
44 import org.eclipse.ui.PlatformUI;
45 import org.eclipse.ui.editors.text.EditorsUI;
46 import org.eclipse.ui.ide.IDE;
47 import org.eclipse.ui.part.MultiPageEditorPart;
48 import org.eclipse.ui.texteditor.ITextEditor;
50 /**
51 * Taken from the Team UI plug in Utils class
53 public class EgitUiEditorUtils {
55 /**
56 * Opens an {@link IFileRevision} is the configured editor.
58 * @param page
59 * to open the editor in
60 * @param revision
61 * to open
62 * @param monitor
63 * for progress reporting
64 * @return the part; may be {@code null} if an external editor was opened
65 * @throws CoreException
67 public static IEditorPart openEditor(IWorkbenchPage page,
68 IFileRevision revision, IProgressMonitor monitor)
69 throws CoreException {
70 SubMonitor progress = SubMonitor.convert(monitor, 2);
71 IStorage file = revision.getStorage(progress.newChild(1));
72 if (file instanceof IFile) {
73 // if this is the current workspace file, open it
74 return IDE.openEditor(page, (IFile) file, OpenStrategy
75 .activateOnOpen());
76 } else {
77 FileRevisionEditorInput fileRevEditorInput = FileRevisionEditorInput
78 .createEditorInputFor(revision, progress.newChild(1));
79 IEditorPart part = openEditor(page, fileRevEditorInput);
80 return part;
84 /**
85 * Opens a text editor on a revision
87 * @param page
88 * the page
89 * @param revision
90 * the revision
91 * @param monitor
92 * a progress monitor, may be null
93 * @throws CoreException
94 * upon failure
96 public static void openTextEditor(IWorkbenchPage page,
97 IFileRevision revision, IProgressMonitor monitor)
98 throws CoreException {
99 SubMonitor progress = SubMonitor.convert(monitor, 1);
100 FileRevisionEditorInput fileRevEditorInput = FileRevisionEditorInput
101 .createEditorInputFor(revision, progress.newChild(1));
102 page.openEditor(fileRevEditorInput, EditorsUI.DEFAULT_TEXT_EDITOR_ID);
106 * Opens an editor for a {@link FileRevisionEditorInput}.
108 * @param page
109 * to open the editor in
110 * @param editorInput
111 * to open
112 * @return the part; may be {@code null} if an external editor was opened
113 * @throws PartInitException
115 public static IEditorPart openEditor(IWorkbenchPage page,
116 FileRevisionEditorInput editorInput) throws PartInitException {
117 return openEditor(page, editorInput, getEditor(editorInput));
121 * @param page
122 * @param editorInput
123 * @param editor
124 * @return the part
125 * @throws PartInitException
127 private static IEditorPart openEditor(IWorkbenchPage page,
128 FileRevisionEditorInput editorInput, IEditorDescriptor editor)
129 throws PartInitException {
130 String editorId = editor.getId();
131 try {
132 IEditorPart part = page.openEditor(editorInput, editorId,
133 OpenStrategy.activateOnOpen());
134 if (part == null && !editor.isOpenExternal()) {
135 throw new PartInitException(NLS.bind(
136 UIText.EgitUiUtils_CouldNotOpenEditorMessage, editorId));
138 return part;
139 } catch (PartInitException e) {
140 if (editorId.equals(EditorsUI.DEFAULT_TEXT_EDITOR_ID)) {
141 throw e;
142 } else {
143 return page.openEditor(editorInput,
144 EditorsUI.DEFAULT_TEXT_EDITOR_ID);
150 * Looks up a resource for the given file and opens an editor on it. A text
151 * editor is opened if the file is not contained in the workspace.
153 * @param file
154 * File to open an editor for. {@code file} must exist.
155 * @param page
156 * @return the created editor or null in case of an error
158 @Nullable
159 public static IEditorPart openEditor(File file, IWorkbenchPage page) {
160 if (!file.exists()) {
161 return null;
163 IPath path = new Path(file.getAbsolutePath());
164 IFile ifile = ResourceUtil.getFileForLocation(path, true);
165 try {
166 if (ifile != null) {
167 return IDE.openEditor(page, ifile,
168 OpenStrategy.activateOnOpen());
169 } else {
170 IFileStore store = EFS.getLocalFileSystem().getStore(path);
171 return IDE.openEditorOnFileStore(page, store);
173 } catch (PartInitException e) {
174 Activator.handleError(UIText.EgitUiEditorUtils_openFailed, e, true);
176 return null;
179 private static IEditorDescriptor getEditor(
180 FileRevisionEditorInput editorInput) {
181 IEditorRegistry registry = PlatformUI.getWorkbench()
182 .getEditorRegistry();
183 String fileName = editorInput.getFileRevision().getName();
184 IContentType type = getContentType(editorInput);
185 IEditorDescriptor descriptor = registry
186 .getDefaultEditor(fileName, type);
187 if (descriptor != null) {
188 descriptor = IDE.overrideDefaultEditorAssociation(editorInput, type,
189 descriptor);
191 if (descriptor == null) {
192 descriptor = registry.findEditor(EditorsUI.DEFAULT_TEXT_EDITOR_ID);
194 return descriptor;
197 private static IContentType getContentType(
198 FileRevisionEditorInput editorInput) {
199 IContentType type = null;
200 try {
201 InputStream contents = editorInput.getStorage().getContents();
202 try {
203 type = getContentType(editorInput.getFileRevision().getName(),
204 contents);
205 } finally {
206 try {
207 contents.close();
208 } catch (IOException e) {
209 // ignore
212 } catch (CoreException e) {
213 Activator.handleError(e.getMessage(), e, false);
215 return type;
218 private static IContentType getContentType(String fileName,
219 InputStream contents) {
220 IContentType type = null;
221 if (contents != null) {
222 try {
223 type = Platform.getContentTypeManager().findContentTypeFor(
224 contents, fileName);
225 } catch (IOException e) {
226 Activator.handleError(e.getMessage(), e, false);
229 if (type == null) {
230 type = Platform.getContentTypeManager()
231 .findContentTypeFor(fileName);
233 return type;
237 * Reveals the given {@code lineNo} if it is greater than zero and the
238 * editor is an {@link ITextEditor}.
240 * @param editor
241 * to reveal the line in
242 * @param lineNo
243 * to reveal
245 public static void revealLine(IEditorPart editor, int lineNo) {
246 if (lineNo < 0) {
247 return;
249 ITextEditor textEditor = getTextEditor(editor);
250 if (textEditor == null) {
251 return;
253 IDocument document = textEditor.getDocumentProvider()
254 .getDocument(textEditor.getEditorInput());
255 if (document == null) {
256 return;
258 try {
259 textEditor.selectAndReveal(document.getLineOffset(lineNo), 0);
260 } catch (BadLocationException e) {
261 // Ignore
265 private static ITextEditor getTextEditor(IEditorPart editor) {
266 if (editor instanceof ITextEditor) {
267 return (ITextEditor) editor;
268 } else if (editor instanceof MultiPageEditorPart) {
269 Object nestedEditor = ((MultiPageEditorPart) editor)
270 .getSelectedPage();
271 if (nestedEditor instanceof ITextEditor) {
272 return (ITextEditor) nestedEditor;
275 return null;