blob: 0f91683b129468071ca8d17f2f9087f9a4567a58 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2007, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.r.ui.preferences;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.typed.BeanProperties;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.databinding.swt.typed.WidgetProperties;
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.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.ecommons.databinding.core.validation.IntegerValidator;
import org.eclipse.statet.ecommons.databinding.jface.DataBindingSupport;
import org.eclipse.statet.ecommons.preferences.core.Preference;
import org.eclipse.statet.ecommons.preferences.ui.ManagedConfigurationBlock;
import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
import org.eclipse.statet.ecommons.text.ui.settings.IndentSettingsUI;
import org.eclipse.statet.ecommons.ui.util.LayoutUtils;
import org.eclipse.statet.r.core.RCodeStyleSettings;
/**
* A PreferenceBlock for RCodeStyleSettings (code formatting preferences).
*/
public class RCodeStylePreferenceBlock extends ManagedConfigurationBlock {
// in future supporting multiple profiles?
// -> we bind to bean not to preferences
private static class Operator {
private final String label;
private final String wsBeforeProp;
private final Preference<Boolean> wsBeforePref;
private final String wsAfterProp;
private final Preference<Boolean> wsAfterPref;
private Button wsBeforeControl;
private Button wsAfterControl;
public Operator(final String label,
final String wsBeforeProp, final Preference<Boolean> wsBeforePref,
final String wsAfterProp, final Preference<Boolean> wsAfterPref) {
this.label= label;
this.wsBeforeProp= wsBeforeProp;
this.wsBeforePref= wsBeforePref;
this.wsAfterProp= wsAfterProp;
this.wsAfterPref= wsAfterPref;
}
}
private RCodeStyleSettings model;
private IndentSettingsUI stdIndentSettings;
private Text indentBlockDepth;
private Text indentGroupDepth;
private Text indentWrappedCommandDepth;
private ImList<Operator> operators;
private Button nlFDefBodyBlockBefore;
public RCodeStylePreferenceBlock(final IProject project, final StatusChangeListener statusListener) {
super(project, statusListener);
}
@Override
protected void createBlockArea(final Composite pageComposite) {
final Map<Preference<?>, String> prefs= new HashMap<>();
prefs.put(RCodeStyleSettings.INDENT_DEFAULT_TYPE_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
prefs.put(RCodeStyleSettings.TAB_SIZE_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
prefs.put(RCodeStyleSettings.INDENT_SPACES_COUNT_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
prefs.put(RCodeStyleSettings.REPLACE_TABS_WITH_SPACES_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
prefs.put(RCodeStyleSettings.REPLACE_CONVERSATIVE_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
prefs.put(RCodeStyleSettings.INDENT_BLOCK_DEPTH_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
prefs.put(RCodeStyleSettings.INDENT_GROUP_DEPTH_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
prefs.put(RCodeStyleSettings.INDENT_WRAPPED_COMMAND_DEPTH_PREF, RCodeStyleSettings.INDENT_GROUP_ID);
this.operators= ImCollections.newList(
new Operator(Messages.RCodeStyle_Whitespace_Assign_label,
RCodeStyleSettings.WS_ASSIGN_BEFORE_PROP, RCodeStyleSettings.WS_ASSIGN_BEFORE_PREF,
RCodeStyleSettings.WS_ASSIGN_AFTER_PROP, RCodeStyleSettings.WS_ASSIGN_AFTER_PREF),
new Operator(Messages.RCodeStyle_Whitespace_ArgAssign_label,
RCodeStyleSettings.WS_ARGASSIGN_BEFORE_PROP, RCodeStyleSettings.WS_ARGASSIGN_BEFORE_PREF,
RCodeStyleSettings.WS_ARGASSIGN_AFTER_PROP, RCodeStyleSettings.WS_ARGASSIGN_AFTER_PREF),
new Operator(Messages.RCodeStyle_Whitespace_OtherOp_label,
RCodeStyleSettings.WS_OTHEROP_BEFORE_PROP, RCodeStyleSettings.WS_OTHEROP_BEFORE_PREF,
RCodeStyleSettings.WS_OTHEROP_AFTER_PROP, RCodeStyleSettings.WS_OTHEROP_AFTER_PREF) );
for (final Operator operator : this.operators) {
prefs.put(operator.wsBeforePref, RCodeStyleSettings.WS_GROUP_ID);
prefs.put(operator.wsAfterPref, RCodeStyleSettings.WS_GROUP_ID);
}
prefs.put(RCodeStyleSettings.NL_FDEF_BODYBLOCK_BEFORE_PREF, RCodeStyleSettings.WS_GROUP_ID);
setupPreferenceManager(prefs);
this.model= new RCodeStyleSettings(0);
this.stdIndentSettings= new IndentSettingsUI();
final Composite mainComposite= new Composite(pageComposite, SWT.NONE);
mainComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
mainComposite.setLayout(LayoutUtils.newCompositeGrid(2));
final TabFolder folder= new TabFolder(mainComposite, SWT.NONE);
folder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
{ final TabItem item= new TabItem(folder, SWT.NONE);
item.setText(this.stdIndentSettings.getGroupLabel());
item.setControl(createIndentControls(folder));
}
{ final TabItem item= new TabItem(folder, SWT.NONE);
item.setText("&More");
item.setControl(createMoreControls(folder));
}
initBindings();
updateControls();
}
private Control createIndentControls(final Composite parent) {
final Composite composite= new Composite(parent, SWT.NONE);
composite.setLayout(LayoutUtils.newTabGrid(2));
this.stdIndentSettings.createControls(composite);
LayoutUtils.addSmallFiller(composite, false);
final Composite depthComposite= new Composite(composite, SWT.NONE);
depthComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
depthComposite.setLayout(LayoutUtils.newCompositeGrid(3));
this.indentBlockDepth= createIndentDepthLine(depthComposite, Messages.RCodeStyle_Indent_IndentInBlocks_label);
this.indentGroupDepth= createIndentDepthLine(depthComposite, Messages.RCodeStyle_Indent_IndentInGroups_label);
this.indentWrappedCommandDepth= createIndentDepthLine(depthComposite, Messages.RCodeStyle_Indent_IndentOfWrappedCommands_label);
return composite;
}
private Text createIndentDepthLine(final Composite composite, final String label) {
final Label labelControl= new Label(composite, SWT.LEFT);
labelControl.setText(label);
labelControl.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
final Text textControl= new Text(composite, SWT.RIGHT | SWT.SINGLE | SWT.BORDER);
final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, false, false);
gd.widthHint= LayoutUtils.hintWidth(textControl, 2);
textControl.setLayoutData(gd);
final Label typeControl= new Label(composite, SWT.LEFT);
typeControl.setText(this.stdIndentSettings.getLevelUnitLabel());
typeControl.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
return textControl;
}
private Control createMoreControls(final Composite parent) {
final Composite composite= new Composite(parent, SWT.NONE);
composite.setLayout(LayoutUtils.newTabGrid(4));
{ final Label label= new Label(composite, SWT.LEFT);
label.setText(Messages.RCodeStyle_Whitespace_label);
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
}
{ final Label label= new Label(composite, SWT.NONE);
label.setText(Messages.RCodeStyle_Whitespace_Before_label);
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
}
{ final Label label= new Label(composite, SWT.NONE);
label.setText(Messages.RCodeStyle_Whitespace_After_label);
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
}
{ final Label dummy = new Label(composite, SWT.NONE);
dummy.setVisible(false);
dummy.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 1, 4));
}
for (final Operator operator : this.operators) {
final Label label= new Label(composite, SWT.NONE);
label.setText(operator.label + "\u200A:"); //$NON-NLS-1$
final GridData gd= new GridData(SWT.FILL, SWT.CENTER, false, false);
gd.horizontalIndent= LayoutUtils.defaultIndent();
label.setLayoutData(gd);
operator.wsBeforeControl= new Button(composite, SWT.CHECK);
operator.wsBeforeControl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
operator.wsAfterControl= new Button(composite, SWT.CHECK);
operator.wsAfterControl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
}
LayoutUtils.addSmallFiller(composite, false);
this.nlFDefBodyBlockBefore= new Button(composite, SWT.CHECK);
this.nlFDefBodyBlockBefore.setText(Messages.RCodeStyle_Newline_FDefBodyBlock_Before_label);
this.nlFDefBodyBlockBefore.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1));
return composite;
}
@Override
protected void addBindings(final DataBindingSupport db) {
this.stdIndentSettings.addBindings(db, this.model);
db.getContext().bindValue(
WidgetProperties.text(SWT.Modify)
.observe(this.indentBlockDepth),
BeanProperties.value(RCodeStyleSettings.class, RCodeStyleSettings.INDENT_BLOCK_DEPTH_PROP, Integer.TYPE)
.observe(db.getRealm(), this.model),
new UpdateValueStrategy<String, Integer>()
.setAfterGetValidator(new IntegerValidator(1, 10,
Messages.RCodeStyle_Indent_IndentInBlocks_error_message )),
null );
db.getContext().bindValue(
WidgetProperties.text(SWT.Modify)
.observe(this.indentGroupDepth),
BeanProperties.value(RCodeStyleSettings.class, RCodeStyleSettings.INDENT_GROUP_DEPTH_PROP, Integer.TYPE)
.observe(db.getRealm(), this.model),
new UpdateValueStrategy<String, Integer>()
.setAfterGetValidator(new IntegerValidator(1, 10,
Messages.RCodeStyle_Indent_IndentInGroups_error_message )),
null );
db.getContext().bindValue(
WidgetProperties.text(SWT.Modify)
.observe(this.indentWrappedCommandDepth),
BeanProperties.value(RCodeStyleSettings.class, RCodeStyleSettings.INDENT_WRAPPED_COMMAND_DEPTH_PROP, Integer.TYPE)
.observe(db.getRealm(), this.model),
new UpdateValueStrategy<String, Integer>()
.setAfterGetValidator(new IntegerValidator(1, 10,
Messages.RCodeStyle_Indent_IndentOfWrappedCommands_error_message )),
null );
for (final Operator operator : this.operators) {
db.getContext().bindValue(
WidgetProperties.buttonSelection()
.observe(operator.wsBeforeControl),
BeanProperties.value(RCodeStyleSettings.class, operator.wsBeforeProp, Boolean.TYPE)
.observe(db.getRealm(), this.model) );
db.getContext().bindValue(
WidgetProperties.buttonSelection()
.observe(operator.wsAfterControl),
BeanProperties.value(RCodeStyleSettings.class, operator.wsAfterProp, Boolean.TYPE)
.observe(db.getRealm(), this.model) );
}
db.getContext().bindValue(
WidgetProperties.buttonSelection()
.observe(this.nlFDefBodyBlockBefore),
BeanProperties.value(RCodeStyleSettings.class, RCodeStyleSettings.NL_FDEF_BODYBLOCK_BEFORE_PROP, Boolean.TYPE)
.observe(db.getRealm(), this.model) );
}
@Override
protected void updateControls() {
this.model.load(this);
this.model.resetDirty();
getDataBinding().getContext().updateTargets(); // required for invalid target values
}
@Override
protected void updatePreferences() {
if (this.model.isDirty()) {
this.model.resetDirty();
setPrefValues(this.model.toPreferencesMap());
}
}
}