blob: d7807948ad151599306e53a56a6f723d71dba443 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2012, 2021 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.pkgmanager;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.Realm;
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.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.databinding.viewers.typed.ViewerProperties;
import org.eclipse.jface.databinding.wizard.WizardPageSupport;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.statet.jcommons.ts.core.Tool;
import org.eclipse.statet.ecommons.databinding.jface.DataBindingSupport;
import org.eclipse.statet.ecommons.ui.dialogs.DialogUtils;
import org.eclipse.statet.ecommons.ui.util.LayoutUtils;
import org.eclipse.statet.ecommons.ui.workbench.ResourceInputComposite;
import org.eclipse.statet.internal.r.ui.RUIPlugin;
import org.eclipse.statet.r.core.pkgmanager.IRPkgData;
import org.eclipse.statet.r.core.pkgmanager.IRPkgManager;
import org.eclipse.statet.r.core.pkgmanager.RPkgAction;
import org.eclipse.statet.r.core.pkgmanager.RPkgUtils;
import org.eclipse.statet.r.ui.RUI;
import org.eclipse.statet.rj.renv.core.RLibLocation;
import org.eclipse.statet.rj.renv.core.RPkgType;
import org.eclipse.statet.rj.renv.runtime.RuntimeRLibPaths;
public class InstallPkgFileWizard extends Wizard {
class Page extends WizardPage {
private static final String FILE_HISTORY= "RPkgFile.history"; //$NON-NLS-1$
private final IObservableValue<String> fileValue;
private final IObservableValue<RPkgType> typeValue;
private final IObservableValue<RLibLocation> targetValue;
private ResourceInputComposite fileControl;
private Label typeControl;
private RLibrarySelectionComposite targetControl;
public Page() {
super("InstallPkgFilePage"); //$NON-NLS-1$
setTitle("Install R Package from File");
setDescription("Select the package file and target location.");
final Realm realm= Realm.getDefault();
this.fileValue= new WritableValue<>(realm, "", String.class); //$NON-NLS-1$
this.typeValue= new WritableValue<>(realm, null, RPkgType.class);
this.targetValue= new WritableValue<>(realm, null, RLibLocation.class);
}
@Override
public void createControl(final Composite parent) {
initializeDialogUnits(parent);
final Composite composite= new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
composite.setLayout(LayoutUtils.newContentGrid(1));
this.fileControl= new ResourceInputComposite(composite,
ResourceInputComposite.STYLE_COMBO | ResourceInputComposite.STYLE_LABEL,
ResourceInputComposite.MODE_FILE | ResourceInputComposite.MODE_OPEN,
"Package &file");
this.fileControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
this.fileControl.setHistory(getDialogSettings().getArray(FILE_HISTORY));
this.typeControl= new Label(composite, SWT.NONE);
this.typeControl.setText("Type: ");
this.typeControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
final RuntimeRLibPaths rLibPaths= InstallPkgFileWizard.this.pkgManager.getRLibPaths();
{ final Group group= new Group(composite, SWT.NONE);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
group.setText("Target Library:");
group.setLayout(LayoutUtils.newGroupGrid(1));
this.targetControl= new RLibrarySelectionComposite(group);
this.targetControl.setLayoutData(this.targetControl.createGD());
this.targetControl.getValidator().setWritable(true);
this.targetControl.setInput(rLibPaths);
}
Dialog.applyDialogFont(composite);
setControl(composite);
final DataBindingSupport databinding= new DataBindingSupport(composite);
addBindings(databinding);
validateType();
this.targetValue.setValue(RPkgUtils.getDefaultInstallLocation(rLibPaths));
WizardPageSupport.create(this, databinding.getContext());
}
protected void addBindings(final DataBindingSupport databinding) {
this.fileControl.getValidator().setOnNotLocal(IStatus.OK);
this.fileControl.getValidator().setFileStoreValidator((final IFileStore store) -> {
if (store.getName().indexOf('_') < 0
|| RPkgUtils.getPkgType(store.getName(), InstallPkgFileWizard.this.pkgManager.getRPlatform()) == null ) {
return ValidationStatus.error("File name must follow the pattern '<package_name>_<version>.<ext>'.");
}
validateType();
return ValidationStatus.ok();
});
databinding.getContext().bindValue(
this.fileControl.getObservable(),
this.fileValue,
new UpdateValueStrategy<String, String>()
.setAfterGetValidator(this.fileControl.getValidator()),
null );
this.fileControl.getTextControl().addListener(SWT.Modify, new Listener() {
@Override
public void handleEvent(final Event event) {
validateType();
}
});
databinding.getContext().bindValue(
ViewerProperties.singleSelection(Object.class)
.observe(this.targetControl.getSelectionViewer()),
this.targetValue,
new UpdateValueStrategy<Object, RLibLocation>()
.setAfterGetValidator(this.targetControl.getValidator()),
null );
}
void validateType() {
RPkgType type= null;
final IFileStore store= this.fileControl.getResourceAsFileStore();
if (store != null) {
type= RPkgUtils.getPkgType(store.getName(), InstallPkgFileWizard.this.pkgManager.getRPlatform());
}
String text= "Type: ";
if (type != null) {
text+= type.getLabel() +
" (" + RPkgUtils.getPkgTypeInstallKey(InstallPkgFileWizard.this.pkgManager.getRPlatform(), type) + ")";
}
this.typeControl.setText(text);
this.typeValue.setValue(type);
}
public IFileStore getFile() {
return this.fileControl.getResourceAsFileStore();
}
public RPkgType getType() {
return this.typeValue.getValue();
}
public RLibLocation getTargetLocation() {
return this.targetValue.getValue();
}
public void saveSettings() {
final IDialogSettings settings= getDialogSettings();
DialogUtils.saveHistorySettings(settings, FILE_HISTORY, this.fileValue.getValue());
}
}
private final Tool rTool;
private final IRPkgManager.Ext pkgManager;
private Page page;
public InstallPkgFileWizard(final Tool rTool, final IRPkgManager.Ext manager) {
this.rTool= rTool;
this.pkgManager= manager;
setWindowTitle("R Package Manager");
setNeedsProgressMonitor(true);
setDialogSettings(DialogUtils.getDialogSettings(RUIPlugin.getInstance(), "pkgmanager/InstallPkgFileWizard")); //$NON-NLS-1$
}
@Override
public void addPages() {
this.page= new Page();
addPage(this.page);
}
@Override
public boolean performFinish() {
this.page.saveSettings();
final IFileStore store= this.page.getFile();
final RLibLocation location= this.page.getTargetLocation();
try {
getContainer().run(true, true, new IRunnableWithProgress() {
@Override
public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
final IRPkgData pkgData= InstallPkgFileWizard.this.pkgManager.addToCache(store, monitor);
final RPkgAction action= new RPkgAction.Install(pkgData, location, null);
InstallPkgFileWizard.this.pkgManager.perform(InstallPkgFileWizard.this.rTool,
Collections.singletonList(action) );
}
catch (final CoreException e) {
throw new InvocationTargetException(e);
}
}
});
}
catch (final InvocationTargetException e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, RUI.BUNDLE_ID,
"An error occurred when preparing the R package installation from file.", e.getCause()));
}
catch (final InterruptedException e) {
}
return true;
}
}