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.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import com.ibm.icu.text.Collator; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.UpdateValueStrategy; import org.eclipse.core.databinding.beans.BeansObservables; import org.eclipse.core.databinding.observable.value.IValueChangeListener; import org.eclipse.core.databinding.observable.value.ValueChangeEvent; import org.eclipse.core.databinding.validation.IValidator; import org.eclipse.core.databinding.validation.ValidationStatus; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.variables.IStringVariableManager; import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; 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.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.statushandlers.StatusManager; import de.walware.ecommons.databinding.jface.DataBindingSupport; import de.walware.ecommons.debug.ui.LaunchConfigUtil; import de.walware.ecommons.debug.ui.ProcessOutputCollector; import de.walware.ecommons.ui.components.ButtonGroup; import de.walware.ecommons.ui.components.DataAdapter; import de.walware.ecommons.ui.components.ExtensibleTextCellEditor; import de.walware.ecommons.ui.dialogs.ExtStatusDialog; import de.walware.ecommons.ui.util.DialogUtil; import de.walware.ecommons.ui.util.LayoutUtil; import de.walware.ecommons.ui.util.MessageUtil; import de.walware.ecommons.ui.util.ViewerUtil; import de.walware.ecommons.ui.util.ViewerUtil.TreeComposite; import de.walware.ecommons.ui.workbench.ResourceInputComposite; import de.walware.statet.r.core.RUtil; import de.walware.statet.r.core.renv.IREnvConfiguration; import de.walware.statet.r.core.renv.IREnvConfiguration.Exec; import de.walware.statet.r.core.renv.IRLibraryGroup; import de.walware.statet.r.core.renv.IRLibraryLocation; import de.walware.statet.r.core.renv.IRLibraryLocation.WorkingCopy; import de.walware.statet.r.internal.ui.RUIPlugin; import de.walware.statet.r.internal.ui.help.IRUIHelpContextIds; import de.walware.statet.r.ui.REnvLabelProvider; import de.walware.statet.r.ui.RUI; /** * Dialog for a local standard {@link IREnvConfiguration} (<code>user-local</code>) */ public class REnvLocalConfigDialog extends ExtStatusDialog { private static final String DETECT_START = "_R-Path-And-Library-Configuration_"; //$NON-NLS-1$ private static final String DETECT_COMMAND = "cat('" + DETECT_START + "'," //$NON-NLS-1$ //$NON-NLS-2$ + "Sys.getenv(\'R_HOME\')," //$NON-NLS-1$ + "Sys.getenv(\'R_ARCH\')," //$NON-NLS-1$ + "paste(.Library,collapse=.Platform$path.sep)," //$NON-NLS-1$ + "paste(.Library.site,collapse=.Platform$path.sep)," //$NON-NLS-1$ + "Sys.getenv('R_LIBS')," //$NON-NLS-1$ + "Sys.getenv('R_LIBS_USER')," //$NON-NLS-1$ + "R.home('doc')," //$NON-NLS-1$ + "R.home('share')," //$NON-NLS-1$ + "R.home('include')," //$NON-NLS-1$ + "R.version$arch," //$NON-NLS-1$ + ".Platform$OS.type," //$NON-NLS-1$ + "sep=intToUtf8(0x0AL));"; //$NON-NLS-1$ private static final int DETECT_LENGTH = 12; private static final int DETECT_R_HOME = 1; private static final int DETECT_R_ARCHVAR = 2; private static final int DETECT_R_DEFAULT = 3; private static final int DETECT_R_SITE = 4; private static final int DETECT_R_OTHER = 5; private static final int DETECT_R_USER = 6; private static final int DETECT_R_DOC_DIR = 7; private static final int DETECT_R_SHARE_DIR = 8; private static final int DETECT_R_INCLUDE_DIR = 9; private static final int DETECT_R_ARCH = 10; private static final int DETECT_R_OS = 11; private static final Pattern DETECT_ITEM_PATTERN = RUtil.LINE_SEPARATOR_PATTERN; private static final Pattern DETECT_PATH_PATTERN = Pattern.compile(Pattern.quote(File.pathSeparator)); private class RHomeComposite extends ResourceInputComposite { public RHomeComposite(final Composite parent) { super(parent, ResourceInputComposite.STYLE_TEXT, ResourceInputComposite.MODE_DIRECTORY | ResourceInputComposite.MODE_OPEN, Messages.REnv_Detail_Location_label); setShowInsertVariable(true, DialogUtil.DEFAULT_NON_ITERACTIVE_FILTERS, null); } @Override protected void fillMenu(final Menu menu) { super.fillMenu(menu); final MenuItem item = new MenuItem(menu, SWT.PUSH); item.setText(Messages.REnv_Detail_Location_FindAuto_label); item.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final String[] rhome = searchRHOME(); if (rhome != null) { setText(rhome[0], true); updateArchs(false); final String current = fNameControl.getText().trim(); if ((current.isEmpty() || current.equals("R")) && rhome[1] != null) { //$NON-NLS-1$ fNameControl.setText(rhome[1]); } } else { final String name = Messages.REnv_Detail_Location_label; MessageDialog.openInformation(getShell(), MessageUtil.removeMnemonics(name), NLS.bind(Messages.REnv_Detail_Location_FindAuto_Failed_message, name)); } getTextControl().setFocus(); } }); } } private static class RLibraryContainer { IRLibraryGroup.WorkingCopy parent; IRLibraryLocation.WorkingCopy library; RLibraryContainer(final IRLibraryGroup.WorkingCopy parent, final IRLibraryLocation.WorkingCopy library) { this.parent = parent; this.library = library; } @Override public boolean equals(final Object obj) { if (!(obj instanceof RLibraryContainer)) { return false; } final RLibraryContainer other = (RLibraryContainer) obj; return (library == other.library); } } private final IREnvConfiguration.WorkingCopy fConfigModel; private final boolean fIsNewConfig; private final Set<String> fExistingNames; private Text fNameControl; private ResourceInputComposite fRHomeControl; private Button fLoadButton; private Combo fRArchControl; private TreeViewer fRLibrariesViewer; private ButtonGroup<IRLibraryLocation.WorkingCopy> fRLibrariesButtons; private ResourceInputComposite fRDocDirectoryControl; private ResourceInputComposite fRShareDirectoryControl; private ResourceInputComposite fRIncludeDirectoryControl; public REnvLocalConfigDialog(final Shell parent, final IREnvConfiguration.WorkingCopy config, final boolean isNewConfig, final Collection<IREnvConfiguration> existingConfigs) { super(parent, WITH_RUNNABLE_CONTEXT | ((isNewConfig) ? WITH_DATABINDING_CONTEXT : (WITH_DATABINDING_CONTEXT | SHOW_INITIAL_STATUS))); fConfigModel = config; fIsNewConfig = isNewConfig; fExistingNames = new HashSet<String>(); for (final IREnvConfiguration ec : existingConfigs) { fExistingNames.add(ec.getName()); } setTitle(fIsNewConfig ? Messages.REnv_Detail_AddDialog_title : Messages.REnv_Detail_Edit_Dialog_title); } @Override public void create() { super.create(); PlatformUI.getWorkbench().getHelpSystem().setHelp(getShell(), IRUIHelpContextIds.R_ENV); } @Override protected Control createDialogArea(final Composite parent) { final Composite area = new Composite(parent, SWT.NONE); area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); area.setLayout(LayoutUtil.createDialogGrid(2)); { // Name: final Label label = new Label(area, SWT.LEFT); label.setText(Messages.REnv_Detail_Name_label + ':'); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); fNameControl = new Text(area, SWT.BORDER); final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.widthHint = LayoutUtil.hintWidth(fNameControl, 60); fNameControl.setLayoutData(gd); fNameControl.setEditable(fConfigModel.isEditable()); } if (fConfigModel.isEditable()) { // Location: final Label label = new Label(area, SWT.LEFT); label.setText(Messages.REnv_Detail_Location_label + ':'); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); fRHomeControl = new RHomeComposite(area); fRHomeControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); } LayoutUtil.addSmallFiller(area, false); { // Architecture / Bits: final Label label = new Label(area, SWT.LEFT); label.setText(Messages.REnv_Detail_Arch_label + ':'); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); final Composite composite = new Composite(area, SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); composite.setLayout(LayoutUtil.createCompositeGrid(3)); { fRArchControl = new Combo(composite, SWT.DROP_DOWN); final GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false); gd.widthHint = LayoutUtil.hintWidth(fRArchControl, 8); fRArchControl.setLayoutData(gd); fRArchControl.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { final int selectionIdx; if (!fRArchControl.getListVisible() && (selectionIdx = fRArchControl.getSelectionIndex()) >= 0) { final String item = fRArchControl.getItem(selectionIdx); } } }); fRArchControl.setEnabled(fConfigModel.isEditable()); } if (fConfigModel.isEditable()) { fLoadButton = new Button(composite, SWT.PUSH); fLoadButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, false, 2, 1)); fLoadButton.setText(Messages.REnv_Detail_DetectSettings_label); fLoadButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(final SelectionEvent e) { detectSettings(); } }); } else { LayoutUtil.addGDDummy(composite, true, 2); } } { // Libraries: final Label label = new Label(area, SWT.LEFT); label.setText(Messages.REnv_Detail_Libraries_label + ":"); //$NON-NLS-1$ label.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); final Composite composite = new Composite(area, SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); composite.setLayout(LayoutUtil.createCompositeGrid(2)); final TreeComposite treeComposite = new ViewerUtil.TreeComposite(composite, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION); fRLibrariesViewer = treeComposite.viewer; final GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.widthHint = LayoutUtil.hintWidth(fNameControl, 80); gd.heightHint = LayoutUtil.hintHeight(treeComposite.tree, 10); treeComposite.setLayoutData(gd); treeComposite.viewer.setContentProvider(new ITreeContentProvider() { @Override public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) { } @Override public void dispose() { } @Override public Object[] getElements(final Object inputElement) { return fConfigModel.getRLibraryGroups().toArray(); } @Override public Object getParent(final Object element) { if (element instanceof RLibraryContainer) { return ((RLibraryContainer) element).parent; } return null; } @Override public boolean hasChildren(final Object element) { if (element instanceof IRLibraryGroup.WorkingCopy) { return !((IRLibraryGroup.WorkingCopy) element).getLibraries().isEmpty(); } return false; } @Override public Object[] getChildren(final Object parentElement) { if (parentElement instanceof IRLibraryGroup.WorkingCopy) { final IRLibraryGroup.WorkingCopy group = (IRLibraryGroup.WorkingCopy) parentElement; final List<? extends IRLibraryLocation.WorkingCopy> libs = group.getLibraries(); final RLibraryContainer[] array = new RLibraryContainer[libs.size()]; for (int i = 0; i < libs.size(); i++) { array[i] = new RLibraryContainer(group, libs.get(i)); } return array; } return null; } }); final TreeViewerColumn column = treeComposite.addColumn(SWT.LEFT, new ColumnWeightData(100)); column.setLabelProvider(new REnvLabelProvider() { @Override public void update(final ViewerCell cell) { final Object element = cell.getElement(); if (element instanceof RLibraryContainer) { final IRLibraryLocation lib = ((RLibraryContainer) element).library; cell.setImage(RUI.getImage(RUI.IMG_OBJ_LIBRARY_LOCATION)); if (lib.getSource() != IRLibraryLocation.USER && lib.getLabel() != null) { cell.setText(lib.getLabel()); } else { cell.setText(lib.getDirectoryPath()); } finishUpdate(cell); return; } super.update(cell); } }); column.setEditingSupport(new EditingSupport(treeComposite.viewer) { @Override protected boolean canEdit(final Object element) { if (element instanceof RLibraryContainer) { final RLibraryContainer container = ((RLibraryContainer) element); return (container.library.getSource() == IRLibraryLocation.USER); } return false; } @Override protected void setValue(final Object element, final Object value) { final RLibraryContainer container = (RLibraryContainer) element; container.library.setDirectoryPath((String) value); getViewer().refresh(container, true); getDataBinding().updateStatus(); } @Override protected Object getValue(final Object element) { final RLibraryContainer container = (RLibraryContainer) element; return container.library.getDirectoryPath(); } @Override protected CellEditor getCellEditor(final Object element) { return new ExtensibleTextCellEditor(treeComposite.tree) { @Override protected Control createCustomControl(final Composite parent) { final ResourceInputComposite chooseResourceComposite = new ResourceInputComposite( parent, ResourceInputComposite.STYLE_TEXT, ResourceInputComposite.MODE_DIRECTORY | ResourceInputComposite.MODE_OPEN, Messages.REnv_Detail_LibraryLocation_label) { @Override protected void beforeMenuAction() { getFocusGroup().discontinueTracking(); } @Override protected void afterMenuAction() { getFocusGroup().continueTracking(); } }; chooseResourceComposite.setShowInsertVariable(true, DialogUtil.DEFAULT_NON_ITERACTIVE_FILTERS, null); fText = (Text) chooseResourceComposite.getTextControl(); return chooseResourceComposite; } }; } }); treeComposite.viewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS); treeComposite.viewer.setInput(fConfigModel); ViewerUtil.installDefaultEditBehaviour(treeComposite.viewer); ViewerUtil.scheduleStandardSelection(treeComposite.viewer); fRLibrariesButtons = new ButtonGroup<IRLibraryLocation.WorkingCopy>(composite) { @Override protected IRLibraryLocation.WorkingCopy edit1(final IRLibraryLocation.WorkingCopy item, final boolean newItem, final Object parent) { if (newItem) { return ((IRLibraryGroup.WorkingCopy) parent).newLibrary(""); //$NON-NLS-1$ } return item; } @Override public void updateState() { super.updateState(); if (getDataAdapter().isDirty()) { getDataBinding().updateStatus(); } } }; fRLibrariesButtons.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true)); fRLibrariesButtons.addAddButton(null); fRLibrariesButtons.addDeleteButton(null); // fRLibrariesButtons.addSeparator(); // fRLibrariesButtons.addUpButton(); // fRLibrariesButtons.addDownButton(); final DataAdapter<IRLibraryLocation.WorkingCopy> adapter = new DataAdapter.ListAdapter<IRLibraryLocation.WorkingCopy>( (ITreeContentProvider) fRLibrariesViewer.getContentProvider(), null, null) { private IRLibraryGroup.WorkingCopy getGroup(final Object element) { if (element instanceof IRLibraryGroup.WorkingCopy) { return (IRLibraryGroup.WorkingCopy) element; } else { return ((RLibraryContainer) element).parent; } } @Override public IRLibraryLocation.WorkingCopy getModelItem(final Object element) { if (element instanceof RLibraryContainer) { return ((RLibraryContainer) element).library; } return (IRLibraryLocation.WorkingCopy) element; } @Override public Object getViewerElement(final IRLibraryLocation.WorkingCopy item, final Object parent) { return new RLibraryContainer((IRLibraryGroup.WorkingCopy.WorkingCopy) parent, item); } @Override public boolean isAddAllowed(final Object element) { return !getGroup(element).getId().equals(IRLibraryGroup.R_DEFAULT); } @Override public boolean isModifyAllowed(final Object element) { return (element instanceof RLibraryContainer && ((RLibraryContainer) element).library.getSource() == IRLibraryLocation.USER); } @Override public Object getAddParent(final Object element) { return getGroup(element); } @Override public List<? super IRLibraryLocation.WorkingCopy> getContainerFor(final Object element) { if (element instanceof IRLibraryGroup.WorkingCopy) { return ((IRLibraryGroup.WorkingCopy) element).getLibraries(); } else { return ((RLibraryContainer) element).parent.getLibraries(); } } }; fRLibrariesButtons.connectTo(fRLibrariesViewer, adapter); } if (fConfigModel.isEditable()) { final Composite group = createInstallDirGroup(area); if (group != null) { group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); } } LayoutUtil.addSmallFiller(area, true); applyDialogFont(area); return area; } private Composite createInstallDirGroup(final Composite parent) { final Group composite = new Group(parent, SWT.NONE); composite.setLayout(LayoutUtil.createGroupGrid(2)); composite.setText("Advanced - Installation locations:"); { final Label label = new Label(composite, SWT.NONE); label.setText("Documentation ('R_DOC_DIR'):"); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); final ResourceInputComposite text = new ResourceInputComposite(composite, ResourceInputComposite.STYLE_TEXT, (ResourceInputComposite.MODE_DIRECTORY | ResourceInputComposite.MODE_OPEN), "R_DOC_DIR"); //$NON-NLS-1$ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); text.setShowInsertVariable(true, DialogUtil.DEFAULT_NON_ITERACTIVE_FILTERS, null); fRDocDirectoryControl = text; } { final Label label = new Label(composite, SWT.NONE); label.setText("Shared files ('R_SHARE_DIR'):"); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); final ResourceInputComposite text = new ResourceInputComposite(composite, ResourceInputComposite.STYLE_TEXT, (ResourceInputComposite.MODE_DIRECTORY | ResourceInputComposite.MODE_OPEN), "R_SHARE_DIR"); //$NON-NLS-1$ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); text.setShowInsertVariable(true, DialogUtil.DEFAULT_NON_ITERACTIVE_FILTERS, null); fRShareDirectoryControl = text; } { final Label label = new Label(composite, SWT.NONE); label.setText("Include files ('R_INCLUDE_DIR'):"); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); final ResourceInputComposite text = new ResourceInputComposite(composite, ResourceInputComposite.STYLE_TEXT, (ResourceInputComposite.MODE_DIRECTORY | ResourceInputComposite.MODE_OPEN), "R_INCLUDE_DIR"); //$NON-NLS-1$ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); text.setShowInsertVariable(true, DialogUtil.DEFAULT_NON_ITERACTIVE_FILTERS, null); fRIncludeDirectoryControl = text; } return composite; } @Override protected void addBindings(final DataBindingSupport db) { db.getContext().bindValue(SWTObservables.observeText(fNameControl, SWT.Modify), BeansObservables.observeValue(fConfigModel, IREnvConfiguration.PROP_NAME), new UpdateValueStrategy().setAfterGetValidator(new IValidator() { @Override public IStatus validate(final Object value) { String s = (String) value; s = s.trim(); if (s.isEmpty()) { return ValidationStatus.error(Messages.REnv_Detail_Name_error_Missing_message); } if (fExistingNames.contains(s)) { return ValidationStatus.error(Messages.REnv_Detail_Name_error_Duplicate_message); } if (s.contains("/")) { //$NON-NLS-1$ return ValidationStatus.error(Messages.REnv_Detail_Name_error_InvalidChar_message); } return ValidationStatus.ok(); } }), null); if (fRHomeControl != null) { final Binding rHomeBinding = db.getContext().bindValue(fRHomeControl.getObservable(), BeansObservables.observeValue(fConfigModel, IREnvConfiguration.PROP_RHOME), new UpdateValueStrategy().setAfterGetValidator(new IValidator() { @Override public IStatus validate(final Object value) { final IStatus status = fRHomeControl.getValidator().validate(value); if (!status.isOK()) { return status; } if (!fConfigModel.isValidRHomeLocation(fRHomeControl.getResourceAsFileStore())) { return ValidationStatus.error(Messages.REnv_Detail_Location_error_NoRHome_message); } updateArchs(!fIsNewConfig); return ValidationStatus.ok(); } }), null); rHomeBinding.getValidationStatus().addValueChangeListener(new IValueChangeListener() { @Override public void handleValueChange(final ValueChangeEvent event) { final IStatus status = (IStatus) event.diff.getNewValue(); fLoadButton.setEnabled(status.isOK()); } }); rHomeBinding.validateTargetToModel(); } db.getContext().bindValue(SWTObservables.observeText(fRArchControl), BeansObservables.observeValue(fConfigModel, IREnvConfiguration.PROP_SUBARCH)); if (fRDocDirectoryControl != null) { db.getContext().bindValue(fRDocDirectoryControl.getObservable(), BeansObservables.observeValue(fConfigModel, IREnvConfiguration.PROP_RDOC_DIRECTORY)); db.getContext().bindValue(fRShareDirectoryControl.getObservable(), BeansObservables.observeValue(fConfigModel, IREnvConfiguration.PROP_RSHARE_DIRECTORY)); db.getContext().bindValue(fRIncludeDirectoryControl.getObservable(), BeansObservables.observeValue(fConfigModel, IREnvConfiguration.PROP_RINCLUDE_DIRECTORY)); } } private String[] searchRHOME() { try { final IStringVariableManager variables = VariablesPlugin.getDefault().getStringVariableManager(); String loc = variables.performStringSubstitution("${env_var:R_HOME}", false); //$NON-NLS-1$ if (loc != null && loc.length() > 0) { if (EFS.getLocalFileSystem().getStore(new Path(loc)).fetchInfo().exists()) { return new String[] { loc, Messages.REnv_SystemRHome_name }; } } if (Platform.getOS().startsWith("win")) { //$NON-NLS-1$ loc = "${env_var:PROGRAMFILES}\\R"; //$NON-NLS-1$ final IFileStore res = EFS.getLocalFileSystem() .getStore(new Path(variables.performStringSubstitution(loc))); if (!res.fetchInfo().exists()) { return null; } final String[] childNames = res.childNames(EFS.NONE, null); Arrays.sort(childNames, 0, childNames.length, Collator.getInstance()); for (int i = childNames.length - 1; i >= 0; i--) { if (fConfigModel.isValidRHomeLocation(res.getChild(childNames[i]))) { return new String[] { loc + '\\' + childNames[i], childNames[i] }; } } } else if (Platform.getOS().equals(Platform.OS_MACOSX)) { loc = "/Library/Frameworks/R.framework/Resources"; //$NON-NLS-1$ if (fConfigModel.isValidRHomeLocation(EFS.getLocalFileSystem().getStore(new Path(loc)))) { return new String[] { loc, null }; } } else { final String[] defLocations = new String[] { "/usr/local/lib64/R", //$NON-NLS-1$ "/usr/lib64/R", //$NON-NLS-1$ "/usr/local/lib/R", //$NON-NLS-1$ "/usr/lib/R", //$NON-NLS-1$ }; for (int i = 0; i < defLocations.length; i++) { try { java.nio.file.Path path = Paths.get(defLocations[i]); path = path.toRealPath(); loc = path.toString(); } catch (final IOException e2) { continue; } if (fConfigModel.isValidRHomeLocation(EFS.getLocalFileSystem().getStore(new Path(loc)))) { return new String[] { loc, null }; } } } } catch (final Exception e) { RUIPlugin.logError(-1, "Error when searching R_HOME location", e); //$NON-NLS-1$ } return null; } private void updateArchs(final boolean conservative) { if (fRHomeControl == null) { return; } try { final IFileStore rHome = fRHomeControl.getResourceAsFileStore(); final List<String> availableArchs = fConfigModel.searchAvailableSubArchs(rHome); if (availableArchs == null) { fRArchControl.setItems(new String[0]); return; } final String oldArch = fRArchControl.getText(); fRArchControl.setItems(availableArchs.toArray(new String[availableArchs.size()])); int idx = (oldArch.length() > 0) ? availableArchs.indexOf(oldArch) : -1; if (idx >= 0) { fRArchControl.select(idx); } if (conservative && fRArchControl.getText().length() > 0) { return; } idx = availableArchs.indexOf(Platform.getOSArch()); if (idx < 0) { if (Platform.getOSArch().equals(Platform.ARCH_X86)) { idx = availableArchs.indexOf("i386"); //$NON-NLS-1$ if (idx < 0) { idx = availableArchs.indexOf("i586"); //$NON-NLS-1$ if (idx < 0) { idx = availableArchs.indexOf("i686"); //$NON-NLS-1$ } } } } if (idx < 0) { idx = 0; } fRArchControl.select(idx); } catch (final Exception e) { fRArchControl.setItems(new String[0]); } } private void detectSettings() { try { run(true, true, new IRunnableWithProgress() { @Override public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { detectSettings(monitor); } catch (final CoreException e) { throw new InvocationTargetException(e); } } }); } catch (final InvocationTargetException e) { final String message = (e.getCause() instanceof CoreException) ? Messages.REnv_Detail_DetectSettings_error_message : Messages.REnv_Detail_DetectSettings_error_Unexpected_message; StatusManager.getManager().handle(new Status(IStatus.ERROR, RUI.PLUGIN_ID, -1, message, e), StatusManager.LOG); StatusManager.getManager().handle(new Status(IStatus.ERROR, RUI.PLUGIN_ID, -1, message, e.getCause()), StatusManager.SHOW); } catch (final InterruptedException e) { } fRLibrariesButtons.refresh(); fRLibrariesViewer.expandAll(); } private void detectSettings(final IProgressMonitor monitor) throws CoreException { monitor.beginTask(Messages.REnv_Detail_DetectSettings_task, 10); final ProcessBuilder processBuilder = new ProcessBuilder(fConfigModel.getExecCommand(Exec.TERM)); processBuilder.command().add("--no-save"); //$NON-NLS-1$ processBuilder.command().add("--slave"); //$NON-NLS-1$ processBuilder.command().add("-e"); //$NON-NLS-1$ processBuilder.command().add(DETECT_COMMAND); final Map<String, String> envp = processBuilder.environment(); LaunchConfigUtil.configureEnvironment(envp, null, fConfigModel.getEnvironmentsVariables(false)); monitor.worked(1); final ProcessOutputCollector reader = new ProcessOutputCollector(processBuilder, "'Detect R settings'", //$NON-NLS-1$ monitor); final String output = reader.collect(); final int start = output.indexOf(DETECT_START); if (start >= 0) { final String[] lines = DETECT_ITEM_PATTERN.split(output.substring(start)); if (lines.length == DETECT_LENGTH) { updateLibraries(fConfigModel.getRLibraryGroup(IRLibraryGroup.R_DEFAULT), lines[DETECT_R_DEFAULT], lines[DETECT_R_HOME]); final IRLibraryGroup.WorkingCopy.WorkingCopy group = fConfigModel .getRLibraryGroup(IRLibraryGroup.R_SITE); updateLibraries(group, lines[DETECT_R_SITE], lines[DETECT_R_HOME]); if (group.getLibraries().isEmpty()) { group.getLibraries().add(group.newLibrary(IRLibraryGroup.DEFAULTLOCATION_R_SITE)); } updateLibraries(fConfigModel.getRLibraryGroup(IRLibraryGroup.R_OTHER), lines[DETECT_R_OTHER], lines[DETECT_R_HOME]); updateLibraries(fConfigModel.getRLibraryGroup(IRLibraryGroup.R_USER), lines[DETECT_R_USER], lines[DETECT_R_HOME]); fConfigModel.setRDocDirectoryPath(checkDir(lines[DETECT_R_DOC_DIR], lines[DETECT_R_HOME])); fConfigModel.setRShareDirectoryPath(checkDir(lines[DETECT_R_SHARE_DIR], lines[DETECT_R_HOME])); fConfigModel.setRIncludeDirectoryPath(checkDir(lines[DETECT_R_INCLUDE_DIR], lines[DETECT_R_HOME])); if (lines[DETECT_R_ARCHVAR].length() > 0) { fConfigModel.setSubArch(lines[DETECT_R_ARCHVAR]); } else if (lines[DETECT_R_ARCH].length() > 0 && fConfigModel.getSubArch() == null) { fConfigModel.setSubArch(lines[DETECT_R_ARCH]); } fConfigModel.setROS(lines[DETECT_R_OS]); return; } } throw new CoreException( new Status(IStatus.ERROR, RUI.PLUGIN_ID, -1, "Unexpected output:\n" + output, null)); //$NON-NLS-1$ } private void updateLibraries(final IRLibraryGroup.WorkingCopy.WorkingCopy group, final String var, final String rHome) { final List<WorkingCopy> libraries = group.getLibraries(); libraries.clear(); final String[] locations = DETECT_PATH_PATTERN.split(var); final IPath rHomePath = new Path(rHome); final IPath userHomePath = new Path(System.getProperty("user.home")); //$NON-NLS-1$ for (final String location : locations) { if (location.isEmpty()) { continue; } String s; final IPath path; if (location.startsWith("~/")) { //$NON-NLS-1$ path = userHomePath.append(location.substring(2)); } else { path = new Path(location); } if (rHomePath.isPrefixOf(path)) { s = "${env_var:R_HOME}/" + path.makeRelativeTo(rHomePath).toString(); //$NON-NLS-1$ } else if (userHomePath.isPrefixOf(path)) { s = "${user_home}/" + path.makeRelativeTo(userHomePath).toString(); //$NON-NLS-1$ } else { s = path.toString(); } libraries.add(group.newLibrary(s)); } } private String checkDir(String dir, final String rHome) { if (dir != null && dir.length() > 0) { final IPath rHomePath = new Path(rHome); final IPath path = new Path(dir); if (rHomePath.isPrefixOf(path)) { dir = "${env_var:R_HOME}/" + path.makeRelativeTo(rHomePath).toString(); //$NON-NLS-1$ } return dir; } return null; } }