| /******************************************************************************* |
| * Copyright (c) 2004, 2013 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 |
| *******************************************************************************/ |
| 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.IProgressMonitor; |
| 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, new String[] { |
| IDialogConstants.YES_LABEL, |
| IDialogConstants.NO_LABEL }, 0) { |
| @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 = new Job(IDEWorkbenchMessages.IDEEncoding_EncodingJob) { |
| @Override |
| protected IStatus run(IProgressMonitor 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 e) {// If there is an error return the |
| // default |
| IDEWorkbenchPlugin |
| .log( |
| IDEWorkbenchMessages.ResourceEncodingFieldEditor_ErrorStoringMessage, |
| e.getStatus()); |
| return e.getStatus(); |
| } catch (BackingStoreException e) { |
| IDEWorkbenchPlugin.log(IDEWorkbenchMessages.ResourceEncodingFieldEditor_ErrorStoringMessage, e); |
| return new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, e.getMessage(), e); |
| } |
| } |
| }; |
| |
| 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); |
| Control[] children = group.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| children[i].setEnabled(enabled); |
| |
| } |
| } |
| |
| } |