blob: fc16cc846ce4c7735e1df666da0e7031e6608a39 [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.r.ui.pkgmanager;
import static org.eclipse.statet.jcommons.status.Status.OK_STATUS;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.status.ErrorStatus;
import org.eclipse.statet.jcommons.status.ProgressMonitor;
import org.eclipse.statet.jcommons.status.Status;
import org.eclipse.statet.jcommons.status.StatusException;
import org.eclipse.statet.ecommons.ui.util.UIAccess;
import org.eclipse.statet.internal.r.ui.pkgmanager.Messages;
import org.eclipse.statet.internal.r.ui.pkgmanager.RPkgManagerDialog;
import org.eclipse.statet.nico.ui.util.ToolMessageDialog;
import org.eclipse.statet.r.console.core.AbstractRDataRunnable;
import org.eclipse.statet.r.console.core.IRDataAdapter;
import org.eclipse.statet.r.console.core.RProcess;
import org.eclipse.statet.r.core.RCore;
import org.eclipse.statet.r.core.pkgmanager.IRPkgManager;
import org.eclipse.statet.r.ui.RUI;
import org.eclipse.statet.rj.renv.core.REnv;
import org.eclipse.statet.rj.renv.runtime.RPkgManager;
import org.eclipse.statet.rj.renv.runtime.RPkgManagerDataset;
import org.eclipse.statet.rj.ts.core.RTool;
import org.eclipse.statet.rj.ts.core.RToolService;
public class RPkgManagerUI {
private static final Map<REnv, RPkgManagerDialog> DIALOGS= new HashMap<>();
private static final int REQUIRED_FEATURES= RPkgManager.INSTALLED | RPkgManager.AVAILABLE;
private static Shell getShell(final IShellProvider shellProvider) {
Shell shell= null;
if (shellProvider != null) {
shell= shellProvider.getShell();
}
if (shell == null) {
shell= UIAccess.getActiveWorkbenchShell(false);
}
return shell;
}
public static IRPkgManager getPackageManager(final RTool tool) {
if (tool instanceof RProcess) {
final REnv env= tool.getREnv();
if (env != null) {
return RCore.getRPkgManager(env);
}
}
return null;
}
public static Status openDialog(final RProcess tool, final Shell parentShell,
final int requestFlags, final @Nullable StartAction startAction) {
final IRPkgManager.Ext manager= (IRPkgManager.Ext) getPackageManager(tool);
if (manager == null) {
return new ErrorStatus(RUI.BUNDLE_ID, "", null);
}
if (manager.request(REQUIRED_FEATURES | requestFlags) == RPkgManager.REQUIRES_UPDATE) {
tool.getQueue().add(new AbstractRDataRunnable("r/pkgmanager/open", //$NON-NLS-1$
Messages.OpenRPkgManager_task) {
@Override
protected void run(final IRDataAdapter r, final ProgressMonitor m) throws StatusException {
manager.update(r, m);
UIAccess.getDisplay(parentShell).asyncExec(new Runnable() {
@Override
public void run() {
openDialog(manager, tool, parentShell, startAction);
}
});
}
});
}
else {
final Display display= UIAccess.getDisplay(parentShell);
if (display.getThread() == Thread.currentThread()) {
openDialog(manager, tool, parentShell, startAction);
}
else {
display.asyncExec(() -> openDialog(manager, tool, parentShell, startAction));
}
}
return OK_STATUS;
}
public static RPkgManagerDialog openDialog(final IRPkgManager.Ext manager,
final RProcess tool, final Shell parentShell,
final @Nullable StartAction startAction) {
final REnv rEnv= manager.getREnv();
RPkgManagerDialog dialog= DIALOGS.get(rEnv);
if (dialog != null && dialog.getShell() != null && !dialog.getShell().isDisposed()) {
dialog.close();
}
dialog= new RPkgManagerDialog(manager, tool, parentShell);
dialog.setBlockOnOpen(false);
DIALOGS.put(rEnv, dialog);
dialog.open();
dialog.getShell().addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(final DisposeEvent e) {
final RPkgManagerDialog d= DIALOGS.get(rEnv);
if (d != null && d.getShell() == e.getSource()) {
DIALOGS.remove(rEnv);
}
}
});
if (startAction != null) {
dialog.start(startAction);
}
return dialog;
}
public static boolean requestRequiredRPkgs(final IRPkgManager.Ext manager,
final List<String> pkgNames,
final RToolService r, final ProgressMonitor m,
final IShellProvider shellProvider, final String message,
final Runnable okRunnable, final Runnable cancelRunnable) throws StatusException {
final RPkgManagerDataset rPkgSet= manager.getDataset(RPkgManager.INSTALLED, r, m);
final List<String> missingPkgs= new ArrayList<>(pkgNames.size());
final StringBuilder sb= new StringBuilder();
for (final String pkgName : pkgNames) {
if (rPkgSet.getInstalled().contains(pkgName)) {
continue;
}
missingPkgs.add(pkgName);
sb.append("\n\t"); //$NON-NLS-1$
sb.append(pkgName);
}
if (sb.length() == 0) {
return true;
}
sb.insert(0, message);
sb.append("\n\nDo you want to install the packages now?");
final RProcess tool= (RProcess) r.getTool();
final Shell shell= getShell(shellProvider);
final Display display= (shell != null) ? shell.getDisplay() : UIAccess.getDisplay();
display.asyncExec(new Runnable() {
@Override
public void run() {
final boolean yes= ToolMessageDialog.openQuestion(tool, shell,
"Required R Packages", sb.toString());
if (yes) {
final RPkgManagerDialog dialog= openDialog(manager, tool, shell,
new StartAction(StartAction.INSTALL, missingPkgs) );
if (okRunnable != null) {
dialog.getShell().addListener(SWT.Close, new Listener() {
@Override
public void handleEvent(final Event event) {
display.asyncExec(okRunnable);
}
});
}
return;
}
if (cancelRunnable != null) {
cancelRunnable.run();
}
}
});
return false;
}
}