blob: fd6172f4b4ad84f663bde7ad979d4b1d66ffb22f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.editors.text;
import java.io.CharConversionException;
import java.io.UnsupportedEncodingException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.action.IAction;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.editors.text.NLSUtility;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.StatusTextEditor;
import org.eclipse.ui.texteditor.TextEditorAction;
/**
* The standard implementation of <code>IEncodingSupport</code>.
* @since 2.0
*/
public class DefaultEncodingSupport implements IEncodingSupport {
/** Internal preference change listener. */
private IPreferenceChangeListener fPreferenceChangeListener;
/** The editor this support is associated with. */
private StatusTextEditor fTextEditor;
/**
* Creates a new encoding support.
*/
public DefaultEncodingSupport() {
super();
}
/**
* Associates this encoding support to the given text editor and initializes this encoding.
*
* @param textEditor the editor
*/
public void initialize(StatusTextEditor textEditor) {
fTextEditor= textEditor;
IEclipsePreferences prefs= InstanceScope.INSTANCE.getNode(ResourcesPlugin.PI_RESOURCES);
fPreferenceChangeListener= event -> {
if (ResourcesPlugin.PREF_ENCODING.equals(event.getKey())) {
// null means: use default
Runnable runnable= () -> setEncoding(null, false);
if (Display.getCurrent() != null)
runnable.run();
else {
// Post runnable into UI thread
Shell shell;
if (fTextEditor != null)
shell= fTextEditor.getSite().getShell();
else
shell= getActiveWorkbenchShell();
Display display;
if (shell != null)
display= shell.getDisplay();
else
display= Display.getDefault();
display.asyncExec(runnable);
}
}
};
prefs.addPreferenceChangeListener(fPreferenceChangeListener);
}
/**
* Disposes this encoding support.
*/
public void dispose() {
IEclipsePreferences prefs= InstanceScope.INSTANCE.getNode(ResourcesPlugin.PI_RESOURCES);
prefs.removePreferenceChangeListener(fPreferenceChangeListener);
fTextEditor= null;
}
/**
* Resets this encoding support. Should be called if, e.g., the input element of the
* associated editor changed.
*/
public void reset() {
}
/**
* Sets the encoding of the editor's input to the given value. If <code>overwrite</code> is
* <code>true</code> the value is set even if the encoding is already set.
*
* @param encoding the new encoding
* @param overwrite <code>true</code> if current encoding should be overwritten
*/
protected void setEncoding(String encoding, boolean overwrite) {
IDocumentProvider p= fTextEditor.getDocumentProvider();
if (p instanceof IStorageDocumentProvider) {
final IEditorInput input= fTextEditor.getEditorInput();
IStorageDocumentProvider provider= (IStorageDocumentProvider)p;
String current= provider.getEncoding(input);
if (!fTextEditor.isDirty()) {
String internal= encoding == null ? "" : encoding; //$NON-NLS-1$
boolean apply= (overwrite || current == null) && !internal.equals(current);
if (apply) {
provider.setEncoding(input, encoding);
Runnable encodingSetter=
() -> fTextEditor.doRevertToSaved();
Display display= fTextEditor.getSite().getShell().getDisplay();
if (display != null && !display.isDisposed())
BusyIndicator.showWhile(display, encodingSetter);
else
encodingSetter.run();
}
}
}
}
@Override
public void setEncoding(String encoding) {
setEncoding(encoding, true);
}
@Override
public String getEncoding() {
IDocumentProvider p= fTextEditor.getDocumentProvider();
if (p instanceof IStorageDocumentProvider) {
IStorageDocumentProvider provider= (IStorageDocumentProvider) p;
return provider.getEncoding(fTextEditor.getEditorInput());
}
return null;
}
@Override
public String getDefaultEncoding() {
IDocumentProvider p= fTextEditor.getDocumentProvider();
if (p instanceof IStorageDocumentProvider) {
IStorageDocumentProvider provider= (IStorageDocumentProvider) p;
return provider.getDefaultEncoding();
}
return null;
}
/**
* Returns a status header for the given status.
*
* @param status the status
* @return a status header for the given status.
*/
public String getStatusHeader(IStatus status) {
Throwable t= status.getException();
if (t instanceof CharConversionException)
return TextEditorMessages.Editor_error_unreadable_encoding_header;
if (t instanceof UnsupportedEncodingException)
return TextEditorMessages.Editor_error_unsupported_encoding_header;
return null;
}
/**
* Returns a banner for the given status.
*
* @param status the status
* @return a banner for the given status.
*/
public String getStatusBanner(IStatus status) {
Throwable t= status.getException();
if (t instanceof CharConversionException)
return TextEditorMessages.Editor_error_unreadable_encoding_banner;
if (t instanceof UnsupportedEncodingException)
return TextEditorMessages.Editor_error_unsupported_encoding_banner;
return null;
}
/**
* Returns a status message if any.
*
* @param status the status
* @return a status message indicating encoding problems or <code>null</code> otherwise
*/
public String getStatusMessage(IStatus status) {
Throwable t= status.getException();
if (t instanceof CharConversionException || t instanceof UnsupportedEncodingException) {
String encoding= getEncoding();
if (encoding == null)
encoding= getDefaultEncoding();
if (t instanceof CharConversionException) {
if (encoding != null)
return NLSUtility.format(TextEditorMessages.Editor_error_unreadable_encoding_message_arg, encoding);
return TextEditorMessages.Editor_error_unreadable_encoding_message;
}
if (t instanceof UnsupportedEncodingException) {
if (encoding != null)
return NLSUtility.format(TextEditorMessages.Editor_error_unsupported_encoding_message_arg, encoding);
return TextEditorMessages.Editor_error_unsupported_encoding_message;
}
}
return null;
}
/**
* Returns <code>true</code> if the given status is an
* encoding error.
*
* @param status the status to check
* @return <code>true</code> if the given status is an encoding error
* @since 3.1
*/
public boolean isEncodingError(IStatus status) {
if (status == null || status.getSeverity() != IStatus.ERROR)
return false;
Throwable t= status.getException();
return t instanceof CharConversionException || t instanceof UnsupportedEncodingException;
}
/**
* Creates the control which allows to change the encoding.
* In case of encoding errors this control will be placed below
* the status of the status editor.
*
* @param parent the parent control
* @param status the status
* @since 3.1
*/
public void createStatusEncodingChangeControl(Composite parent, final IStatus status) {
final IAction action= fTextEditor.getAction(ITextEditorActionConstants.CHANGE_ENCODING);
if (action instanceof TextEditorAction)
((TextEditorAction)action).update();
if (action == null || !action.isEnabled())
return;
Shell shell= parent.getShell();
Display display= shell.getDisplay();
Color bgColor= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
Button button= new Button(parent, SWT.PUSH | SWT.FLAT);
button.setText(action.getText());
button.addSelectionListener(new SelectionAdapter() {
/*
* @see org.eclipse.swt.events.SelectionAdapter#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
action.run();
}
});
button.setFocus();
Label filler= new Label(parent, SWT.NONE);
filler.setLayoutData(new GridData(GridData.FILL_BOTH));
filler.setBackground(bgColor);
}
/**
* Returns the shell of the active workbench window.
*
* @return the shell of the active workbench window or <code>null</code> if none
* @since 3.2
*/
private static Shell getActiveWorkbenchShell() {
IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null)
return window.getShell();
return null;
}
}