/*
* Copyright 2009-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.eclipse.preferences;
import org.codehaus.groovy.eclipse.GroovyPlugin;
import org.codehaus.groovy.eclipse.core.GroovyCoreActivator;
import org.codehaus.groovy.eclipse.core.builder.GroovyClasspathContainerInitializer;
import org.codehaus.groovy.eclipse.core.compiler.CompilerCheckerParticipant;
import org.codehaus.groovy.eclipse.core.compiler.CompilerUtils;
import org.codehaus.groovy.eclipse.core.preferences.PreferenceConstants;
import org.codehaus.groovy.frameworkadapter.util.SpecifiedVersion;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.groovy.core.Activator;
import org.eclipse.jdt.internal.ui.preferences.PropertyAndPreferencePage;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.IWorkbenchPropertyPage;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.osgi.service.prefs.BackingStoreException;
public class CompilerPreferencesPage extends PropertyAndPreferencePage implements IWorkbenchPreferencePage, IWorkbenchPropertyPage {
public static final String PREFERENCES_ID = "org.codehaus.groovy.eclipse.preferences.compiler";
public static final String PROPERTY_ID = Activator.USING_PROJECT_PROPERTIES;
private IEclipsePreferences preferences;
private SpecifiedVersion currentProjectVersion;
private Button groovyLibCheckbox;
private ComboViewer compilerCombo;
private Button compilerMismatchCheckbox;
private ScriptFolderSelectorPreferences scriptFolderSelector;
@Override
protected Label createDescriptionLabel(Composite parent) {
// create the project compiler drop-down above the usual "Enable project specific settings" checkbox
if (isProjectPreferencePage()) {
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 2;
Composite panel = new Composite(parent, SWT.NONE);
panel.setFont(parent.getFont());
panel.setLayout(layout);
panel.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
createProjectCompilerSection(panel);
}
return super.createDescriptionLabel(parent);
}
@Override
protected Control createPreferenceContent(Composite parent) {
getPreferenceStore(); // ensure preferences are loaded for both modes
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 1;
Composite panel = new Composite(parent, SWT.NONE);
panel.setFont(parent.getFont());
panel.setLayout(layout);
if (!isProjectPreferencePage()) {
createWorkspaceCompilerSection(panel);
}
scriptFolderSelector = new ScriptFolderSelectorPreferences(panel, preferences, getPreferenceStore(), getProject());
scriptFolderSelector.createListContents();
if (!isProjectPreferencePage()) {
createClasspathContainerSection(panel);
}
return panel;
}
private void createProjectCompilerSection(Composite parent) {
Label compilerLabel = new Label(parent, SWT.WRAP);
compilerLabel.setFont(parent.getFont());
compilerLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
compilerLabel.setText("Groovy compiler level for project " + getProject().getName() + ":");
compilerCombo = new ComboViewer(new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY));
compilerCombo.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
return element instanceof SpecifiedVersion ? ((SpecifiedVersion) element).toReadableVersionString() : "";
}
});
compilerCombo.add(SpecifiedVersion.DONT_CARE);
for (SpecifiedVersion version : CompilerUtils.getAllGroovyVersions()) {
compilerCombo.add(version);
}
currentProjectVersion = CompilerUtils.getCompilerLevel(getProject());
compilerCombo.setSelection(new StructuredSelection(currentProjectVersion), true);
Label explainLabel = new Label(parent, SWT.WRAP);
GridData data = new GridData();
data.horizontalSpan = 2;
data.grabExcessHorizontalSpace = false;
explainLabel.setLayoutData(data);
explainLabel.setText(" If the project compiler level does not match the workspace compiler level,\n there will be a build error placed on the project.");
}
private void createWorkspaceCompilerSection(Composite parent) {
Label compilerLabel = new Label(parent, SWT.WRAP);
compilerLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
compilerLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
compilerLabel.setText("Groovy Compiler settings:");
Composite compilerPage = new Composite(parent, SWT.NONE | SWT.BORDER);
GridLayout layout = new GridLayout();
layout.marginHeight = 3;
layout.marginWidth = 3;
layout.numColumns = 1;
compilerPage.setLayout(layout);
compilerPage.setFont(parent.getFont());
compilerPage.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
CompilerSwitchUIHelper.createCompilerSwitchBlock(compilerPage);
compilerMismatchCheckbox = new Button(compilerPage, SWT.CHECK);
compilerMismatchCheckbox.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
compilerMismatchCheckbox.setSelection(getCompilerCheckPref());
compilerMismatchCheckbox.setText("Enable checking for mismatches between the project and workspace Groovy compiler levels");
}
private void createClasspathContainerSection(Composite parent) {
Label gccLabel = new Label(parent, SWT.WRAP);
gccLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
gccLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
gccLabel.setText("Groovy Classpath Container:");
Composite subsection = new Composite(parent, SWT.BORDER);
GridLayout layout = new GridLayout();
layout.marginHeight = 3;
layout.marginWidth = 3;
layout.numColumns = 1;
subsection.setLayout(layout);
subsection.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
groovyLibCheckbox = new Button(subsection, SWT.CHECK);
groovyLibCheckbox.setSelection(getGroovyLibsPref());
groovyLibCheckbox.setText("Include all jars in ~/.groovy/lib on the classpath");
GridData layoutData = new GridData(SWT.FILL, SWT.TOP, true, false);
layoutData.widthHint = 400;
Label groovyLibLabel = new Label(subsection, SWT.WRAP);
groovyLibLabel.setLayoutData(layoutData);
groovyLibLabel.setText("This is the default setting and individual projects can be configured by clicking on the properties page of the Groovy Support classpath container.");
@SuppressWarnings("unused")
Label spacerLabel = new Label(subsection, SWT.WRAP);
Button updateButton = new Button(subsection, SWT.PUSH);
updateButton.setText("Update all Groovy Classpath Containers");
updateButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
updateClasspathContainers();
}
public void widgetDefaultSelected(SelectionEvent e) {
updateClasspathContainers();
}
});
Label updateLabel = new Label(subsection, SWT.WRAP);
updateLabel.setLayoutData(layoutData);
updateLabel.setText("Perform this action if there are changes to ~/.groovy/lib that should be reflected in your projects' classpaths.");
}
@Override
protected IPreferenceStore doGetPreferenceStore() {
IScopeContext scope = (isProjectPreferencePage() ? new ProjectScope(getProject()) : InstanceScope.INSTANCE);
preferences = scope.getNode(Activator.PLUGIN_ID);
IPreferenceStore store = new ScopedPreferenceStore(scope, Activator.PLUGIN_ID);
store.setDefault(Activator.GROOVY_SCRIPT_FILTERS_ENABLED, Activator.DEFAULT_SCRIPT_FILTERS_ENABLED);
return store;
}
@Override
protected void enablePreferenceContent(boolean enable) {
super.enablePreferenceContent(enable);
if (enable) scriptFolderSelector.enableControls();
}
@Override
protected void performDefaults() {
if (compilerCombo != null) {
compilerCombo.setSelection(new StructuredSelection(SpecifiedVersion.DONT_CARE), true);
}
if (compilerMismatchCheckbox != null) {
compilerMismatchCheckbox.setSelection(true);
}
if (groovyLibCheckbox != null) {
groovyLibCheckbox.setSelection(true);
}
scriptFolderSelector.restoreDefaults();
super.performDefaults(); // allow controls to update before project-specific settings callbacks
if (!isProjectPreferencePage())
enablePreferenceContent(true);
}
@Override
public boolean performOk() {
if (compilerCombo != null) {
StructuredSelection selection = (StructuredSelection) compilerCombo.getSelection();
SpecifiedVersion selected = (SpecifiedVersion) selection.getFirstElement();
if (selected == null) {
selected = SpecifiedVersion.UNSPECIFIED;
}
if (selected != currentProjectVersion && selected != SpecifiedVersion.UNSPECIFIED) {
CompilerUtils.setCompilerLevel(getProject(), selected, true);
}
}
if (compilerMismatchCheckbox != null) {
boolean isSelected = compilerMismatchCheckbox.getSelection();
boolean currentPref = getCompilerCheckPref();
if (!isSelected && currentPref) {
// delete all markers in the workspace
try {
ResourcesPlugin.getWorkspace().getRoot().deleteMarkers(CompilerCheckerParticipant.COMPILER_MISMATCH_PROBLEM, true, IResource.DEPTH_ONE);
} catch (CoreException e) {
GroovyPlugin.getDefault().logError("Error deleting markers", e);
}
}
if (isSelected != currentPref) {
setCompilerCheckPref(isSelected);
}
}
if (!isProjectPreferencePage()) {
setGroovyLibsPref(groovyLibCheckbox.getSelection());
} else {
getPreferenceStore().setValue(PROPERTY_ID, useProjectSettings());
}
scriptFolderSelector.applyPreferences();
return super.performOk();
}
@Override
protected boolean hasProjectSpecificOptions(IProject project) {
if (project != null && project.equals(getProject())) {
return getPreferenceStore().getBoolean(PROPERTY_ID);
}
return false;
}
@Override
protected String getPreferencePageID() {
return PREFERENCES_ID;
}
@Override
protected String getPropertyPageID() {
return PROPERTY_ID;
}
//--------------------------------------------------------------------------
private boolean getCompilerCheckPref() {
return preferences.getBoolean(Activator.GROOVY_CHECK_FOR_COMPILER_MISMATCH, true);
}
private void setCompilerCheckPref(boolean value) {
preferences.putBoolean(Activator.GROOVY_CHECK_FOR_COMPILER_MISMATCH, value);
try {
preferences.flush();
} catch (BackingStoreException e) {
GroovyPlugin.getDefault().logError("Error saving compiler preferences", e);
}
}
private boolean getGroovyLibsPref() {
IEclipsePreferences corePrefs = GroovyCoreActivator.getDefault().getPreferences();
return corePrefs.getBoolean(PreferenceConstants.GROOVY_CLASSPATH_USE_GROOVY_LIB_GLOBAL, true);
}
private void setGroovyLibsPref(boolean value) {
IEclipsePreferences corePrefs = GroovyCoreActivator.getDefault().getPreferences();
corePrefs.putBoolean(PreferenceConstants.GROOVY_CLASSPATH_USE_GROOVY_LIB_GLOBAL, value);
try {
corePrefs.flush();
} catch (BackingStoreException e) {
GroovyPlugin.getDefault().logError("Error saving groovy libs preference", e);
}
}
private void updateClasspathContainers() {
try {
GroovyClasspathContainerInitializer.updateAllGroovyClasspathContainers();
} catch (JavaModelException e) {
GroovyPlugin.getDefault().logError("Problem updating Groovy classpath contianers", e);
}
}
}