| /*=============================================================================# |
| # 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()); |
| } |
| } |
| |
| } |