| /*=============================================================================# |
| # Copyright (c) 2010, 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.console.ui.tools; |
| |
| import static org.eclipse.statet.r.launching.RRunDebugPreferenceConstants.ASK; |
| import static org.eclipse.statet.r.launching.RRunDebugPreferenceConstants.AUTO; |
| import static org.eclipse.statet.r.launching.RRunDebugPreferenceConstants.DISABLED; |
| import static org.eclipse.statet.r.launching.RRunDebugPreferenceConstants.PREF_RENV_CHECK_UPDATE; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.eclipse.core.runtime.preferences.InstanceScope; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Label; |
| |
| import org.eclipse.statet.jcommons.status.InfoStatus; |
| 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.jcommons.ts.core.SystemRunnable; |
| import org.eclipse.statet.jcommons.ts.core.Tool; |
| import org.eclipse.statet.jcommons.ts.core.ToolService; |
| |
| import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils; |
| import org.eclipse.statet.ecommons.ui.util.LayoutUtils; |
| import org.eclipse.statet.ecommons.ui.util.UIAccess; |
| |
| import org.eclipse.statet.internal.r.console.ui.Messages; |
| import org.eclipse.statet.internal.r.console.ui.RConsoleUIPlugin; |
| import org.eclipse.statet.internal.r.console.ui.WorkbenchREnvIndexUpdater; |
| import org.eclipse.statet.nico.core.runtime.ToolProcess; |
| 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.RConsoleTool; |
| import org.eclipse.statet.r.console.core.RProcess; |
| import org.eclipse.statet.r.core.RCore; |
| import org.eclipse.statet.r.core.pkgmanager.IRPkgChangeSet; |
| import org.eclipse.statet.r.core.pkgmanager.IRPkgManager; |
| import org.eclipse.statet.r.nico.impl.RjsController; |
| import org.eclipse.statet.rhelp.core.REnvHelpConfiguration; |
| import org.eclipse.statet.rhelp.core.update.REnvIndexChecker; |
| import org.eclipse.statet.rhelp.core.update.REnvIndexUpdater; |
| import org.eclipse.statet.rj.renv.core.REnvConfiguration; |
| |
| |
| public class REnvIndexAutoUpdater { |
| |
| |
| public static void connect(final RProcess process, final IRPkgManager manager) { |
| final REnvConfiguration config= process.getAdapter(REnvConfiguration.class); |
| if (config instanceof REnvHelpConfiguration |
| && config.getStateSharedType() == REnvConfiguration.SHARED_DIRECTORY) { |
| final CheckRunnable checker= new CheckRunnable(process, (REnvHelpConfiguration) config, manager); |
| process.getQueue().addOnIdle(checker, 1100); |
| return; |
| } |
| } |
| |
| |
| public static final class UpdateRunnable extends AbstractRDataRunnable { |
| |
| |
| private final boolean completely; |
| |
| |
| public UpdateRunnable(final boolean completely) { |
| super("r/index/update", Messages.REnvIndex_Update_task); //$NON-NLS-1$ |
| this.completely= completely; |
| } |
| |
| |
| @Override |
| public boolean changed(final int event, final Tool tool) { |
| if (event == MOVING_FROM) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| protected void run(final IRDataAdapter r, final ProgressMonitor m) throws StatusException { |
| REnvConfiguration rEnvConfig= r.getTool().getAdapter(REnvConfiguration.class); |
| if (rEnvConfig != null) { |
| rEnvConfig= rEnvConfig.getREnv().get(REnvConfiguration.class); |
| if (rEnvConfig != null) { |
| final String remoteAddress= r.getWorkspaceData().getRemoteAddress(); |
| final Map<String, String> properties= new HashMap<>(); |
| if (remoteAddress != null) { |
| properties.put("renv.hostname", remoteAddress); //$NON-NLS-1$ |
| } |
| |
| final IRPkgManager rPkgManager= RCore.getRPkgManager(rEnvConfig.getREnv()); |
| rPkgManager.check(IRPkgManager.NONE, r, m); |
| |
| r.handleStatus(new InfoStatus(RConsoleUIPlugin.BUNDLE_ID, |
| Messages.REnvIndex_Update_Started_message ), m ); |
| final REnvIndexUpdater updater= new WorkbenchREnvIndexUpdater( |
| (REnvHelpConfiguration) rEnvConfig, RCore.getRHelpManager(), rPkgManager ); |
| final Status status= updater.update(r, this.completely, properties, m); |
| r.handleStatus(status, m); |
| } |
| } |
| } |
| } |
| |
| |
| private static class AskDialog extends ToolMessageDialog { |
| |
| |
| private Button rememberSessionControl; |
| private Button rememberGloballyControl; |
| |
| private boolean rememberSession; |
| private boolean rememberGlobally; |
| |
| |
| public AskDialog(final ToolProcess tool, final String message) { |
| super(tool, null, Messages.REnvIndex_CheckDialog_title, null, message, QUESTION, |
| new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0); |
| } |
| |
| |
| @Override |
| protected Control createMessageArea(final Composite parent) { |
| super.createMessageArea(parent); |
| |
| LayoutUtils.addGDDummy(parent); |
| final Composite composite= new Composite(parent, SWT.NONE); |
| composite.setLayout(LayoutUtils.newCompositeGrid(1)); |
| |
| { final Label label= new Label(composite, SWT.NONE); |
| label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); |
| label.setText(Messages.REnvIndex_CheckDialog_Remember_label); |
| } |
| { final Button button= new Button(composite, SWT.CHECK); |
| final GridData gd= new GridData(SWT.FILL, SWT.FILL, true, false); |
| gd.horizontalIndent= LayoutUtils.defaultIndent(); |
| button.setLayoutData(gd); |
| button.setText(Messages.REnvIndex_CheckDialog_RememberSession_label); |
| this.rememberSessionControl= button; |
| } |
| { final Button button= new Button(composite, SWT.CHECK); |
| final GridData gd= new GridData(SWT.FILL, SWT.FILL, true, false); |
| gd.horizontalIndent= LayoutUtils.defaultIndent(); |
| button.setLayoutData(gd); |
| button.setText(Messages.REnvIndex_CheckDialog_RememberGlobally_label); |
| this.rememberGloballyControl= button; |
| } |
| |
| this.rememberGloballyControl.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetSelected(final SelectionEvent e) { |
| if (AskDialog.this.rememberGloballyControl.getSelection()) { |
| AskDialog.this.rememberSessionControl.setSelection(false); |
| } |
| } |
| @Override |
| public void widgetDefaultSelected(final SelectionEvent e) { |
| } |
| }); |
| this.rememberSessionControl.addSelectionListener(new SelectionListener() { |
| @Override |
| public void widgetSelected(final SelectionEvent e) { |
| if (AskDialog.this.rememberSessionControl.getSelection()) { |
| AskDialog.this.rememberGloballyControl.setSelection(false); |
| } |
| } |
| @Override |
| public void widgetDefaultSelected(final SelectionEvent e) { |
| } |
| }); |
| |
| return composite; |
| } |
| |
| |
| @Override |
| public boolean close() { |
| this.rememberGlobally= this.rememberGloballyControl.getSelection(); |
| this.rememberSession= this.rememberSessionControl.getSelection(); |
| |
| return super.close(); |
| } |
| |
| } |
| |
| private static class CheckRunnable implements SystemRunnable, IRPkgManager.Listener { |
| |
| |
| private final RProcess process; |
| |
| private final REnvIndexChecker checker; |
| |
| private final IRPkgManager manager; |
| private boolean changed; |
| |
| private String sessionSetting; |
| |
| |
| public CheckRunnable(final RProcess process, final REnvHelpConfiguration config, |
| final IRPkgManager manager) { |
| this.process= process; |
| this.manager= manager; |
| this.changed= true; |
| this.checker= new REnvIndexChecker(config, RCore.getRHelpManager(), manager); |
| |
| this.manager.addListener(this); |
| } |
| |
| |
| @Override |
| public String getTypeId() { |
| return "r/index/check"; //$NON-NLS-1$ |
| } |
| |
| @Override |
| public String getLabel() { |
| return Messages.REnvIndex_Check_task; |
| } |
| |
| @Override |
| public boolean canRunIn(final Tool tool) { |
| return (tool.isProvidingFeatureSet(RConsoleTool.R_DATA_FEATURESET_ID)); |
| } |
| |
| @Override |
| public boolean changed(final int event, final Tool tool) { |
| if (event == MOVING_FROM) { |
| return false; |
| } |
| if (event == BEING_ABANDONED) { |
| this.manager.removeListener(this); |
| } |
| return true; |
| } |
| |
| @Override |
| public void handleChange(final IRPkgManager.Event event) { |
| if ((event.pkgsChanged() & IRPkgManager.INSTALLED) != 0) { |
| final IRPkgChangeSet changeSet= event.getInstalledPkgChangeSet(); |
| if (changeSet != null && !changeSet.getNames().isEmpty()) { |
| this.changed= true; |
| } |
| } |
| } |
| |
| @Override |
| public void run(final ToolService service, final ProgressMonitor m) throws StatusException { |
| final RjsController r= (RjsController) service; // interface? |
| if (r.isBusy() || !r.isDefaultPrompt() || !this.changed ) { |
| return; |
| } |
| this.changed= false; |
| try { |
| final String global= PreferenceUtils.getInstancePrefs().getPreferenceValue(PREF_RENV_CHECK_UPDATE).intern(); |
| |
| if (global == DISABLED |
| || (global == ASK && this.sessionSetting == DISABLED) ) { |
| return; |
| } |
| final int check= this.checker.check(r, m); |
| final String message; |
| |
| if (this.checker.wasAlreadyReported()) { |
| return; |
| } |
| switch (check) { |
| case REnvIndexChecker.NOT_AVAILABLE: |
| case REnvIndexChecker.UP_TO_DATE: |
| return; |
| case REnvIndexChecker.PACKAGES: |
| message= NLS.bind(((this.checker.getNewPackageCount() + this.checker.getChangedPackageCount()) == 1) ? |
| Messages.REnvIndex_Check_Changed_singular_message : |
| Messages.REnvIndex_Check_Changed_plural_message, |
| this.checker.getNewPackageCount(), this.checker.getChangedPackageCount()); |
| break; |
| case REnvIndexChecker.COMPLETE: |
| message= Messages.REnvIndex_Check_NoIndex_message; |
| break; |
| default: |
| return; |
| } |
| |
| if (global != AUTO && this.sessionSetting == null) { |
| final AtomicBoolean update= new AtomicBoolean(); |
| UIAccess.getDisplay().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| final AskDialog dialog= new AskDialog(CheckRunnable.this.process, message); |
| update.set(dialog.open() == 0); |
| if (dialog.rememberGlobally) { |
| PreferenceUtils.setPrefValue(InstanceScope.INSTANCE, |
| PREF_RENV_CHECK_UPDATE, update.get() ? AUTO : DISABLED, |
| PreferenceUtils.FLUSH_ASYNC ); |
| } |
| else if (dialog.rememberSession) { |
| CheckRunnable.this.sessionSetting= update.get() ? AUTO : DISABLED; |
| } |
| } |
| }); |
| if (!update.get()) { |
| return; |
| } |
| } |
| |
| // schedule update |
| service.getTool().getQueue().add(new UpdateRunnable(check == REnvIndexChecker.COMPLETE)); |
| } |
| catch (final StatusException e) { |
| if (e.getStatus().getSeverity() == Status.CANCEL) { |
| throw e; |
| } |
| RConsoleUIPlugin.logError(Messages.REnvIndex_Check_error_message, e); |
| } |
| finally { |
| this.checker.release(); |
| } |
| } |
| } |
| |
| |
| } |