Java tutorial
/*=============================================================================# # Copyright (c) 2007-2015 Stephan Wahlbrink (WalWare.de) 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: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.statet.r.internal.debug.ui.preferences; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.ValidationStatusProvider; import org.eclipse.core.databinding.observable.Observables; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.observable.value.WritableValue; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.jface.databinding.viewers.ViewersObservables; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.IElementComparer; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.ui.statushandlers.StatusManager; import de.walware.ecommons.IStatusChangeListener; import de.walware.ecommons.databinding.jface.DataBindingSupport; import de.walware.ecommons.preferences.IPreferenceAccess; import de.walware.ecommons.preferences.Preference; import de.walware.ecommons.preferences.PreferencesUtil; import de.walware.ecommons.preferences.ui.ConfigurationBlock; import de.walware.ecommons.preferences.ui.ConfigurationBlockPreferencePage; import de.walware.ecommons.preferences.ui.ManagedConfigurationBlock; import de.walware.ecommons.ui.SharedMessages; import de.walware.ecommons.ui.components.ButtonGroup; import de.walware.ecommons.ui.components.DataAdapter; import de.walware.ecommons.ui.components.DropDownButton; import de.walware.ecommons.ui.util.LayoutUtil; import de.walware.ecommons.ui.util.ViewerUtil; import de.walware.ecommons.ui.util.ViewerUtil.TableComposite; import de.walware.statet.r.core.RCore; import de.walware.statet.r.core.RCorePreferenceNodes; import de.walware.statet.r.core.renv.IREnv; import de.walware.statet.r.core.renv.IREnvConfiguration; import de.walware.statet.r.core.renv.IREnvManager; import de.walware.statet.r.internal.ui.help.IRUIHelpContextIds; import de.walware.statet.r.launching.RRunDebugPreferenceConstants; import de.walware.statet.r.ui.RUI; /** * Preference page for R (Environment) configuration of the workbench. */ public class REnvPreferencePage extends ConfigurationBlockPreferencePage { public static final String PREF_PAGE_ID = "de.walware.statet.r.preferencePages.REnvironmentPage"; //$NON-NLS-1$ public REnvPreferencePage() { } @Override protected ConfigurationBlock createConfigurationBlock() throws CoreException { return new REnvConfigurationBlock(null, createStatusChangedListener()); } } class REnvConfigurationBlock extends ManagedConfigurationBlock implements ButtonGroup.IActions<IREnvConfiguration.WorkingCopy> { private final static int ADD_NEW_DEFAULT = ButtonGroup.ADD_NEW; private final static int ADD_NEW_REMOTE = ButtonGroup.ADD_NEW | (0x1 << 8); private TableViewer fListViewer; private ButtonGroup<IREnvConfiguration.WorkingCopy> fListButtons; private final IObservableList fList = new WritableList(); private final IObservableValue fDefault = new WritableValue(); private final IObservableValue fListStatus = new WritableValue(); private ComboViewer fIndexConsoleViewer; private Button fNetworkEclipseControl; protected REnvConfigurationBlock(final IProject project, final IStatusChangeListener statusListener) { super(project, statusListener); } @Override protected String getHelpContext() { return IRUIHelpContextIds.R_ENV; } @Override protected void createBlockArea(final Composite pageComposite) { final Map<Preference<?>, String> prefs = new HashMap<Preference<?>, String>(); prefs.put(RRunDebugPreferenceConstants.PREF_RENV_CHECK_UPDATE, null); setupPreferenceManager(prefs); final Label label = new Label(pageComposite, SWT.LEFT); label.setText(Messages.REnv_REnvList_label); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); { // Table area final Composite composite = new Composite(pageComposite, SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); composite.setLayout(LayoutUtil.createCompositeGrid(2)); final Composite table = createTable(composite); { final GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.heightHint = LayoutUtil.hintHeight(fListViewer.getTable(), 12, false); table.setLayoutData(gd); } fListButtons = new ButtonGroup<IREnvConfiguration.WorkingCopy>(composite, this, false); fListButtons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true)); final SelectionListener addDefaultListener = new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { fListButtons.editElement(ADD_NEW_DEFAULT, null); } }; final DropDownButton addButton = new DropDownButton(fListButtons); final Menu addMenu = addButton.getDropDownMenu(); { final MenuItem menuItem = new MenuItem(addMenu, SWT.PUSH); menuItem.setText(Messages.REnv_Add_Local_label); menuItem.addSelectionListener(addDefaultListener); } { final MenuItem menuItem = new MenuItem(addMenu, SWT.PUSH); menuItem.setText(Messages.REnv_Add_Remote_label); menuItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { fListButtons.editElement(ADD_NEW_REMOTE, null); } }); } addButton.addSelectionListener(addDefaultListener); addButton.setText(SharedMessages.CollectionEditing_AddItem_label + "..."); addButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); fListButtons.addCopyButton(null); fListButtons.addEditButton(null); fListButtons.addDeleteButton(null); fListButtons.addSeparator(); fListButtons.addDefaultButton(null); fListButtons.connectTo(fListViewer, new DataAdapter.ListAdapter<IREnvConfiguration.WorkingCopy>(fList, fDefault) { @Override public boolean isDeleteAllowed(final Object element) { final IREnvConfiguration config = (IREnvConfiguration) element; return config.isEditable(); } }); fListViewer.setComparer(new IElementComparer() { @Override public int hashCode(final Object element) { if (element instanceof IREnvConfiguration) { return ((IREnvConfiguration) element).getReference().hashCode(); } return element.hashCode(); } @Override public boolean equals(final Object a, final Object b) { if (a instanceof IREnvConfiguration && b instanceof IREnvConfiguration) { return ((IREnvConfiguration) a).getReference() .equals(((IREnvConfiguration) b).getReference()); } return a.equals(b); } }); fListViewer.setInput(fList); ViewerUtil.scheduleStandardSelection(fListViewer); } loadValues(PreferencesUtil.getInstancePrefs()); final Composite indexOptions = createIndexOptions(pageComposite); indexOptions.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); final Composite networkOptions = createNetworkOptions(pageComposite); networkOptions.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); initBindings(); updateStatus(); final DataBindingContext dbc = getDataBinding().getContext(); dbc.addValidationStatusProvider(new ValidationStatusProvider() { @Override public IObservableValue getValidationStatus() { return fListStatus; } @Override public IObservableList getModels() { return Observables.staticObservableList(dbc.getValidationRealm(), Collections.emptyList()); } @Override public IObservableList getTargets() { return Observables.staticObservableList(dbc.getValidationRealm(), Collections.emptyList()); } }); updateControls(); fListButtons.refresh(); } @Override public IREnvConfiguration.WorkingCopy edit(final int command, final IREnvConfiguration.WorkingCopy config, final Object parent) { final boolean newConfig = ((command & ButtonGroup.ADD_ANY) != 0); final IREnvConfiguration.WorkingCopy editConfig; if (newConfig) { if (config != null) { // copy editConfig = RCore.getREnvManager().newConfiguration(config.getType()); editConfig.load(config); } else { // add if (command == ADD_NEW_REMOTE) { editConfig = RCore.getREnvManager().newConfiguration(IREnvConfiguration.USER_REMOTE_TYPE); } else { editConfig = RCore.getREnvManager().newConfiguration(IREnvConfiguration.USER_LOCAL_TYPE); } } } else { editConfig = config.createWorkingCopy(); } if (doEdit(editConfig, newConfig)) { if (newConfig) { return editConfig; } else { config.load(editConfig); return config; } } return null; } private boolean doEdit(final IREnvConfiguration.WorkingCopy config, final boolean newConfig) { final List<IREnvConfiguration> existingConfigs = new ArrayList<IREnvConfiguration>(fList); if (!newConfig) { for (final Iterator<IREnvConfiguration> iter = existingConfigs.iterator(); iter.hasNext();) { final IREnvConfiguration existing = iter.next(); if (existing.getReference() == config.getReference()) { iter.remove(); break; } } } Dialog dialog; if (config.isLocal()) { dialog = new REnvLocalConfigDialog(getShell(), config, newConfig, existingConfigs); } else if (config.isRemote()) { dialog = new REnvRemoteConfigDialog(getShell(), config, newConfig, existingConfigs); } else { return false; } return (dialog.open() == Dialog.OK); } @Override public void updateState(final IStructuredSelection selection) { REnvConfigurationBlock.this.updateStatus(); } private Composite createTable(final Composite parent) { final TableComposite composite = new ViewerUtil.TableComposite(parent, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL); fListViewer = composite.viewer; composite.table.setHeaderVisible(true); composite.table.setLinesVisible(true); { final TableViewerColumn column = new TableViewerColumn(composite.viewer, SWT.NONE); composite.layout.setColumnData(column.getColumn(), new ColumnWeightData(1)); column.getColumn().setText(Messages.REnv_NameColumn_name); column.setLabelProvider(new REnvLabelProvider(fDefault)); } { final TableViewerColumn column = new TableViewerColumn(composite.viewer, SWT.NONE); composite.layout.setColumnData(column.getColumn(), new ColumnWeightData(1)); column.getColumn().setText(Messages.REnv_LocationColumn_name); column.setLabelProvider(new ColumnLabelProvider() { @Override public Image getImage(final Object element) { return super.getImage(element); } @Override public String getText(final Object element) { final IREnvConfiguration config = (IREnvConfiguration) element; if (config.getType() == IREnvConfiguration.USER_LOCAL_TYPE) { return config.getRHome(); } if (config.getType() == IREnvConfiguration.EPLUGIN_LOCAL_TYPE) { return "<embedded>"; } return ""; //$NON-NLS-1$ } }); } composite.viewer.setContentProvider(new ArrayContentProvider()); // Sorter composite.viewer.setComparator(new ViewerComparator() { @Override public int compare(final Viewer viewer, final Object e1, final Object e2) { return getComparator().compare(((IREnvConfiguration) e1).getName(), ((IREnvConfiguration) e2).getName()); } }); return composite; } private Composite createIndexOptions(final Composite parent) { final Group composite = new Group(parent, SWT.NONE); composite.setLayout(LayoutUtil.createGroupGrid(2)); composite.setText(Messages.REnv_Index_label); final Label label = new Label(composite, SWT.NONE); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); label.setText(Messages.REnv_Update_Console_label); fIndexConsoleViewer = new ComboViewer(composite, SWT.DROP_DOWN | SWT.READ_ONLY); fIndexConsoleViewer.getControl().setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false)); fIndexConsoleViewer.setLabelProvider(new LabelProvider() { @Override public String getText(final Object element) { if (element.equals(RRunDebugPreferenceConstants.AUTO)) { return Messages.REnv_Update_Console_Auto_label; } if (element.equals(RRunDebugPreferenceConstants.ASK)) { return Messages.REnv_Update_Console_Ask_label; } if (element.equals(RRunDebugPreferenceConstants.DISABLED)) { return Messages.REnv_Update_Console_Disabled_label; } return ""; //$NON-NLS-1$ } }); fIndexConsoleViewer.setContentProvider(new ArrayContentProvider()); fIndexConsoleViewer.setInput(new String[] { RRunDebugPreferenceConstants.AUTO, RRunDebugPreferenceConstants.ASK, RRunDebugPreferenceConstants.DISABLED, }); return composite; } private Composite createNetworkOptions(final Composite parent) { final Group composite = new Group(parent, SWT.NONE); composite.setLayout(LayoutUtil.createGroupGrid(2)); composite.setText(Messages.REnv_Network_label); { final Composite line = new Composite(composite, SWT.NONE); line.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); final GridLayout layout = LayoutUtil.createCompositeGrid(2); layout.horizontalSpacing = 0; line.setLayout(layout); fNetworkEclipseControl = new Button(line, SWT.CHECK); final int idx = Messages.REnv_Network_UseEclipse_label.indexOf("<a"); fNetworkEclipseControl.setText(Messages.REnv_Network_UseEclipse_label.substring(0, idx).trim()); fNetworkEclipseControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); final Link link = addLinkControl(line, Messages.REnv_Network_UseEclipse_label.substring(idx)); link.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); } return composite; } @Override protected void addBindings(final DataBindingSupport db) { db.getContext().bindValue(ViewersObservables.observeSingleSelection(fIndexConsoleViewer), createObservable(RRunDebugPreferenceConstants.PREF_RENV_CHECK_UPDATE)); db.getContext().bindValue(SWTObservables.observeSelection(fNetworkEclipseControl), createObservable(RCorePreferenceNodes.PREF_RENV_NETWORK_USE_ECLIPSE)); } @Override public void performApply() { super.performApply(); saveValues(true); } @Override public boolean performOk() { final boolean superOk = super.performOk(); if (fListButtons.getDataAdapter().isDirty()) { return superOk | saveValues(false); } return superOk; } private void updateStatus() { fListStatus.setValue((fDefault.getValue() == null) ? ValidationStatus.warning(Messages.REnv_warning_NoDefaultConfiguration_message) : ValidationStatus.ok()); } private boolean saveValues(final boolean saveStore) { try { final IREnvConfiguration defaultREnv = (IREnvConfiguration) fDefault.getValue(); final String[] groupIds = RCore.getREnvManager().set( (IREnvConfiguration[]) fList.toArray(new IREnvConfiguration[fList.size()]), (defaultREnv != null) ? defaultREnv.getReference().getId() : null); if (groupIds != null) { ConfigurationBlock.scheduleChangeNotification(getContainer(), groupIds, saveStore); } return true; } catch (final CoreException e) { StatusManager.getManager().handle( new Status(IStatus.ERROR, RUI.PLUGIN_ID, -1, Messages.REnv_error_Saving_message, e), StatusManager.LOG | StatusManager.SHOW); return false; } } private void loadValues(final IPreferenceAccess prefs) { fList.clear(); fDefault.setValue(null); final IREnvManager manager = RCore.getREnvManager(); final IREnv defaultEnv = manager.getDefault().resolve(); final List<IREnvConfiguration> rEnvConfigs = manager.getConfigurations(); for (final IREnvConfiguration rEnvConfig : rEnvConfigs) { final IREnvConfiguration config = rEnvConfig.createWorkingCopy(); fList.add(config); if (config.getReference() == defaultEnv) { fDefault.setValue(config); } } } }