blob: 1b26e77226b39edec41ecaa9a09ca671d8492169 [file] [log] [blame]
/*=============================================================================#
# 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();
}
}
}
}