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