blob: b18a74f5b89846e8747b12b3e63eb1a491620691 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 2017 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.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
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.ui.statushandlers.StatusManager;
import org.eclipse.statet.ecommons.preferences.core.util.PreferenceUtils;
import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
import org.eclipse.statet.ecommons.ts.core.Tool;
import org.eclipse.statet.ecommons.ts.core.ToolService;
import org.eclipse.statet.ecommons.ui.util.LayoutUtil;
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.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.core.pkgmanager.IRPkgManager.Event;
import org.eclipse.statet.r.core.renv.IREnvConfiguration;
import org.eclipse.statet.r.core.rhelp.rj.RJREnvIndexChecker;
import org.eclipse.statet.r.core.rhelp.rj.RJREnvIndexUpdater;
import org.eclipse.statet.r.nico.impl.RjsController;
public class REnvIndexAutoUpdater {
public static void connect(final RProcess process, final IRPkgManager manager) {
final IREnvConfiguration rEnvConfig= process
.getAdapter(IREnvConfiguration.class);
if (rEnvConfig != null) {
final CheckRunnable checker= new CheckRunnable(process, manager,
new RJREnvIndexChecker(rEnvConfig) );
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 IProgressMonitor monitor) throws CoreException {
IREnvConfiguration rEnvConfig= r.getTool().getAdapter(IREnvConfiguration.class);
if (rEnvConfig != null) {
rEnvConfig= rEnvConfig.getReference().getConfig();
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.getReference());
rPkgManager.check(IRPkgManager.NONE, r, monitor);
r.handleStatus(new Status(IStatus.INFO, RConsoleUIPlugin.BUNDLE_ID, -1,
Messages.REnvIndex_Update_Started_message, null ), monitor);
final RJREnvIndexUpdater updater= new RJREnvIndexUpdater(rEnvConfig);
final IStatus status= updater.update(r, this.completely, properties, monitor);
r.handleStatus(status, monitor);
}
}
}
}
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);
LayoutUtil.addGDDummy(parent);
final Composite composite= new Composite(parent, SWT.NONE);
composite.setLayout(LayoutUtil.createCompositeGrid(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= LayoutUtil.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= LayoutUtil.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 RJREnvIndexChecker checker;
private final IRPkgManager manager;
private boolean changed;
private String sessionSetting;
public CheckRunnable(final RProcess process, final IRPkgManager manager, final RJREnvIndexChecker checker) {
this.process= process;
this.manager= manager;
this.changed= true;
this.checker= checker;
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 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 IProgressMonitor monitor) throws CoreException {
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, monitor);
final String message;
if (this.checker.wasAlreadyReported()) {
return;
}
switch (check) {
case RJREnvIndexChecker.NOT_AVAILABLE:
case RJREnvIndexChecker.UP_TO_DATE:
return;
case RJREnvIndexChecker.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 RJREnvIndexChecker.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);
}
else if (dialog.rememberSession) {
CheckRunnable.this.sessionSetting= update.get() ? AUTO : DISABLED;
}
}
});
if (!update.get()) {
return;
}
}
// schedule update
service.getTool().getQueue().add(new UpdateRunnable(false));
}
catch (final CoreException e) {
if (e.getStatus().getSeverity() == IStatus.CANCEL) {
throw e;
}
StatusManager.getManager().handle(new Status(IStatus.ERROR, RConsoleUIPlugin.BUNDLE_ID, -1,
Messages.REnvIndex_Check_error_message, e ));
}
}
}
}