/******************************************************************************* * Copyright (c) 2004, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Tom Hochstein (Freescale) - Bug 409996 - 'Restore Defaults' does not work properly on Project Properties > Resource tab * Lars Vogel <Lars.Vogel@vogella.com> - Bug 472784, 474273 *******************************************************************************/ package org.eclipse.ui.ide.dialogs; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.content.IContentDescription; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.DialogPage; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.WorkbenchEncoding; import org.eclipse.ui.ide.IDEEncoding; import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; /** * The ResourceEncodingFieldEditor is a field editor for editing the encoding of * a resource and does not use a preference store. * <p> * This class may be instantiated; it is not intended to be subclassed. * </p> * * @since 3.1 */ public final class ResourceEncodingFieldEditor extends AbstractEncodingFieldEditor { private static boolean DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS = ResourcesPlugin.DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS; /** * The resource being edited. */ private IResource resource; private Composite group; private Button separateDerivedEncodingsButton = null; /** * Creates a new encoding field editor for setting the encoding on the given * resource. * * @param labelText * the label text of the field editor * @param parent * the parent of the field editor's control * @param charsetResource * must be an <code>IContainer</code> or an <code>IFile</code>. * * @see org.eclipse.core.resources.IContainer#getDefaultCharset() * @see org.eclipse.core.resources.IFile#getCharset() */ public ResourceEncodingFieldEditor(String labelText, Composite parent, IResource charsetResource) { super(); setLabelAndResource(labelText, charsetResource); createControl(parent); } /** * Creates a new encoding field editor for setting the encoding on the given * resource. * * @param labelText * the label text of the field editor * @param parent * the parent of the field editor's control * @param charsetResource * must be an <code>IContainer</code> or an <code>IFile</code>. * @param groupTitle * the title for the field editor's control. If groupTitle is * <code>null</code> the control will be unlabelled * (by default a {@link Composite} instead of a {@link Group}. * * @see org.eclipse.core.resources.IContainer#getDefaultCharset() * @see org.eclipse.core.resources.IFile#getCharset() * @see AbstractEncodingFieldEditor#setGroupTitle(String) * @since 3.3 */ public ResourceEncodingFieldEditor(String labelText, Composite parent, IResource charsetResource,String groupTitle) { super(); setLabelAndResource(labelText, charsetResource); setGroupTitle(groupTitle); createControl(parent); } /** * Set the label text and the resource we are editing. * @param labelText * @param charsetResource * @since 3.3 */ private void setLabelAndResource(String labelText, IResource charsetResource) { Assert.isTrue(charsetResource instanceof IContainer || charsetResource instanceof IFile); setLabelText(labelText); this.resource = charsetResource; } @Override protected String getStoredValue() { try { if (resource instanceof IContainer) { return ((IContainer) resource).getDefaultCharset(false); } return ((IFile) resource).getCharset(false); } catch (CoreException e) {// If there is an error return the default IDEWorkbenchPlugin .log( IDEWorkbenchMessages.ResourceEncodingFieldEditor_ErrorLoadingMessage, e.getStatus()); return WorkbenchEncoding.getWorkbenchDefaultEncoding(); } } private boolean getStoredSeparateDerivedEncodingsValue() { // be careful looking up for our node so not to create any nodes as side effect Preferences node = Platform.getPreferencesService().getRootNode() .node(ProjectScope.SCOPE); String projectName = resource.getName(); try { //TODO once bug 90500 is fixed, should be as simple as this: // String path = projectName + IPath.SEPARATOR + ResourcesPlugin.PI_RESOURCES; // return node.nodeExists(path) ? node.node(path).getBoolean(ResourcesPlugin.PREF_SEPARATE_DERIVED_ENCODINGS, false) : false; // for now, take the long way if (!node.nodeExists(projectName)) return DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS; node = node.node(projectName); if (!node.nodeExists(ResourcesPlugin.PI_RESOURCES)) return DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS; node = node.node(ResourcesPlugin.PI_RESOURCES); return node.getBoolean( ResourcesPlugin.PREF_SEPARATE_DERIVED_ENCODINGS, DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS); } catch (BackingStoreException e) { // default value return DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS; } } private boolean hasSameSeparateDerivedEncodings() { return (separateDerivedEncodingsButton == null) || ((separateDerivedEncodingsButton != null) && (separateDerivedEncodingsButton .getSelection() == getStoredSeparateDerivedEncodingsValue())); } @Override protected void doStore() { String encoding = getSelectedEncoding(); // Clear the value if nothing is selected if (isDefaultSelected()) { encoding = null; } // Don't update if the same thing is selected final boolean hasSameEncoding = hasSameEncoding(encoding); final boolean hasSameSeparateDerivedEncodings = hasSameSeparateDerivedEncodings(); if (hasSameEncoding && hasSameSeparateDerivedEncodings) { return; } String descriptionCharset = getCharsetFromDescription(); if (descriptionCharset != null && !(descriptionCharset.equals(encoding)) && encoding != null) { Shell shell = null; DialogPage page = getPage(); if (page != null) { shell = page.getShell(); } MessageDialog dialog = new MessageDialog( shell, IDEWorkbenchMessages.ResourceEncodingFieldEditor_EncodingConflictTitle, null, NLS.bind(IDEWorkbenchMessages.ResourceEncodingFieldEditor_EncodingConflictMessage, encoding, descriptionCharset), MessageDialog.WARNING, 0, IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL) { @Override protected int getShellStyle() { return super.getShellStyle() | SWT.SHEET; } }; // yes is the // default if (dialog.open() > 0) { return; } } IDEEncoding.addIDEEncoding(encoding); final String finalEncoding = encoding; Job charsetJob = Job.create(IDEWorkbenchMessages.IDEEncoding_EncodingJob, monitor -> { try { if (!hasSameEncoding) { if (resource instanceof IContainer) { ((IContainer) resource).setDefaultCharset( finalEncoding, monitor); } else { ((IFile) resource).setCharset(finalEncoding, monitor); } } if (!hasSameSeparateDerivedEncodings) { Preferences prefs = new ProjectScope((IProject) resource).getNode(ResourcesPlugin.PI_RESOURCES); boolean newValue = !getStoredSeparateDerivedEncodingsValue(); // Remove the pref if it's the default, otherwise store it. if (newValue == DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS) prefs.remove(ResourcesPlugin.PREF_SEPARATE_DERIVED_ENCODINGS); else prefs.putBoolean(ResourcesPlugin.PREF_SEPARATE_DERIVED_ENCODINGS, newValue); prefs.flush(); } return Status.OK_STATUS; } catch (CoreException e1) {// If there is an error return the // default IDEWorkbenchPlugin .log( IDEWorkbenchMessages.ResourceEncodingFieldEditor_ErrorStoringMessage, e1.getStatus()); return e1.getStatus(); } catch (BackingStoreException e2) { IDEWorkbenchPlugin.log(IDEWorkbenchMessages.ResourceEncodingFieldEditor_ErrorStoringMessage, e2); return new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, e2.getMessage(), e2); } }); charsetJob.schedule(); } @Override public void store() { // Override the store method as we are not using a preference store doStore(); } @Override public void load() { // Override the load method as we are not using a preference store setPresentsDefaultValue(false); doLoad(); } @Override public void loadDefault() { // Override the loadDefault method as we are not using a preference store setPresentsDefaultValue(true); doLoadDefault(); refreshValidState(); } @Override protected void doLoadDefault() { super.doLoadDefault(); if (separateDerivedEncodingsButton != null) separateDerivedEncodingsButton.setSelection(DEFAULT_PREF_SEPARATE_DERIVED_ENCODINGS); } @Override protected String findDefaultEncoding() { if (resource instanceof IWorkspaceRoot) { return super.findDefaultEncoding(); } String defaultCharset = getCharsetFromDescription(); if (defaultCharset != null && defaultCharset.length() > 0) { return defaultCharset; } try { // Query up the whole hierarchy defaultCharset = resource.getParent().getDefaultCharset(true); } catch (CoreException exception) { // If there is an exception try again } if (defaultCharset != null && defaultCharset.length() > 0) { return defaultCharset; } return super.findDefaultEncoding(); } /** * Returns the charset from the content description if there is one. * * @return the charset from the content description, or <code>null</code> */ private String getCharsetFromDescription() { IContentDescription description = getContentDescription(); if (description != null) { return description.getCharset(); } return null; } @Override protected String defaultButtonText() { if (resource instanceof IWorkspaceRoot) { return super.defaultButtonText(); } if (resource instanceof IFile) { try { IContentDescription description = ((IFile) resource) .getContentDescription(); // If we can find a charset from the description then derive // from that if (description == null || description.getCharset() == null) { return NLS .bind( IDEWorkbenchMessages.ResourceInfo_fileContainerEncodingFormat, getDefaultEnc()); } IContentType contentType = description.getContentType(); if (contentType != null && contentType.getDefaultCharset() == description.getCharset()) { return NLS .bind( IDEWorkbenchMessages.ResourceInfo_fileContentTypeEncodingFormat, getDefaultEnc()); } return NLS .bind( IDEWorkbenchMessages.ResourceInfo_fileContentEncodingFormat, getDefaultEnc()); } catch (CoreException exception) { // Do nothing here as we will just try to derive from the // container } } return NLS.bind( IDEWorkbenchMessages.ResourceInfo_containerEncodingFormat, getDefaultEnc()); } @Override protected Composite createEncodingGroup(Composite parent, int numColumns) { group = super.createEncodingGroup(parent, numColumns); String byteOrderLabel = IDEEncoding .getByteOrderMarkLabel(getContentDescription()); if (byteOrderLabel != null) { Label label = new Label(group, SWT.NONE); label .setText(NLS .bind( IDEWorkbenchMessages.WorkbenchPreference_encoding_encodingMessage, byteOrderLabel)); GridData layoutData = new GridData(); layoutData.horizontalSpan = numColumns + 1; label.setLayoutData(layoutData); } if (resource.getType() == IResource.PROJECT) { separateDerivedEncodingsButton = new Button(group, SWT.CHECK); GridData data = new GridData(); data.horizontalSpan = 2; separateDerivedEncodingsButton.setLayoutData(data); separateDerivedEncodingsButton .setText(IDEWorkbenchMessages.ResourceEncodingFieldEditor_SeparateDerivedEncodingsLabel); separateDerivedEncodingsButton .setSelection(getStoredSeparateDerivedEncodingsValue()); } return group; } /** * Returns the content description of the resource if it is a file and it * has a content description. * * @return the content description or <code>null</code> if resource is not * an <code>IFile</code> or it does not have a description */ private IContentDescription getContentDescription() { try { if (resource instanceof IFile) { return (((IFile) resource).getContentDescription()); } } catch (CoreException exception) { // If we cannot find it return null } return null; } @Override public void setEnabled(boolean enabled, Composite parent) { super.setEnabled(enabled, parent); group.setEnabled(enabled); for (Control child : group.getChildren()) { child.setEnabled(enabled); } } }