| /*=============================================================================# |
| # 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.internal.r.ui.pkgmanager; |
| |
| import org.eclipse.core.databinding.observable.ChangeEvent; |
| import org.eclipse.core.databinding.observable.IChangeListener; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.preference.PreferenceDialog; |
| import org.eclipse.jface.wizard.WizardDialog; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| 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.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.TabFolder; |
| import org.eclipse.swt.widgets.TabItem; |
| import org.eclipse.ui.services.IServiceLocator; |
| |
| import org.eclipse.statet.jcommons.status.Status; |
| |
| import org.eclipse.statet.ecommons.databinding.jface.DataBindingSupport; |
| import org.eclipse.statet.ecommons.runtime.core.util.StatusUtils; |
| import org.eclipse.statet.ecommons.ui.components.StatusInfo; |
| import org.eclipse.statet.ecommons.ui.dialogs.DialogUtils; |
| import org.eclipse.statet.ecommons.ui.util.LayoutUtils; |
| import org.eclipse.statet.ecommons.ui.util.NestedServices; |
| import org.eclipse.statet.ecommons.ui.util.UIAccess; |
| |
| import org.eclipse.statet.internal.r.ui.RUIPlugin; |
| import org.eclipse.statet.nico.ui.util.ToolDialog; |
| import org.eclipse.statet.nico.ui.util.ToolInfoGroup; |
| import org.eclipse.statet.r.console.core.RProcess; |
| import org.eclipse.statet.r.core.pkgmanager.IRPkgManager; |
| import org.eclipse.statet.r.core.pkgmanager.IRPkgSet; |
| import org.eclipse.statet.r.core.pkgmanager.ISelectedRepos; |
| import org.eclipse.statet.r.core.renv.IREnvConfiguration; |
| import org.eclipse.statet.r.ui.pkgmanager.StartAction; |
| import org.eclipse.statet.rj.renv.runtime.RPkgManager; |
| |
| |
| public class RPkgManagerDialog extends ToolDialog implements IChangeListener, IRPkgManager.Listener { |
| |
| static final int APPLY_ID= 10; |
| static final int INSTFILE_ID= 12; |
| |
| static final Object[] NO_INPUT= new Object[0]; |
| |
| |
| private final IRPkgManager.Ext rPkgManager; |
| |
| private Display display; |
| |
| private IStatus status; |
| |
| private TabFolder tabFolder; |
| private PkgTab pkgTab; |
| private RepoTab repoTab; |
| private OptionsTab optionsTab; |
| |
| private Button applyButton; |
| |
| private final Object updateLock= new Object(); |
| private boolean updateRepos; |
| private boolean updatePkgs; |
| private boolean updateState; |
| private int updatePage; |
| |
| private StartAction startAction; |
| |
| private NestedServices uiServices; |
| |
| |
| public RPkgManagerDialog(final IRPkgManager.Ext rPkgManager, final RProcess rProcess, |
| final Shell parentShell) { |
| super(rProcess, parentShell, null, "R Package Manager", ToolInfoGroup.WIDE); |
| |
| this.rPkgManager= rPkgManager; |
| } |
| |
| |
| @Override |
| protected IDialogSettings getDialogBoundsSettings() { |
| return DialogUtils.getDialogSettings(RUIPlugin.getInstance(), "pkgmanager/MainDialog"); //$NON-NLS-1$ |
| } |
| |
| |
| @Override |
| protected RProcess getTool() { |
| return (RProcess) super.getTool(); |
| } |
| |
| @Override |
| protected void setShellStyle(final int newShellStyle) { |
| super.setShellStyle((newShellStyle & ~SWT.APPLICATION_MODAL) | SWT.MIN | SWT.MAX); |
| } |
| |
| @Override |
| public void create() { |
| super.create(); |
| |
| updateStatus(); |
| } |
| |
| @Override |
| protected Control createContents(final Composite parent) { |
| final Control control= super.createContents(parent); |
| |
| setTitle(NLS.bind("R Package Manager for ''{0}''", this.rPkgManager.getREnv().getName())); |
| |
| setTabFocus(); |
| |
| if (this.rPkgManager.getReposStatus(null).getSeverity() != Status.OK) { |
| activateTab(this.repoTab.getTab()); |
| } |
| else { |
| onTabSelected(this.pkgTab.getTab()); |
| } |
| |
| this.display= parent.getDisplay(); |
| this.rPkgManager.addListener(this); |
| parent.addDisposeListener(new DisposeListener() { |
| @Override |
| public void widgetDisposed(final DisposeEvent e) { |
| RPkgManagerDialog.this.rPkgManager.removeListener(RPkgManagerDialog.this); |
| } |
| }); |
| |
| this.uiServices= new NestedServices.Dialog(getShell()); |
| this.pkgTab.createActions(); |
| |
| return control; |
| } |
| |
| protected final IServiceLocator getServiceLocator() { |
| return this.uiServices.getLocator(); |
| } |
| |
| protected final PkgTab getPkgTab() { |
| return this.pkgTab; |
| } |
| |
| protected final RepoTab getRepoTab() { |
| return this.repoTab; |
| } |
| |
| protected final OptionsTab getOptionsTab() { |
| return this.optionsTab; |
| } |
| |
| @Override |
| protected Control createDialogContent(final Composite parent) { |
| final Composite composite= new Composite(parent, SWT.NONE); |
| composite.setLayout(LayoutUtils.newCompositeGrid(1)); |
| |
| this.tabFolder= new TabFolder(composite, SWT.TOP); |
| this.tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| |
| { final TabItem tabItem= new TabItem(this.tabFolder, SWT.NONE); |
| tabItem.setText("&Packages"); |
| this.pkgTab= new PkgTab(this, tabItem, this.tabFolder, this.rPkgManager); |
| tabItem.setControl(this.pkgTab); |
| } |
| { final TabItem tabItem= new TabItem(this.tabFolder, SWT.NONE); |
| tabItem.setText("&Repositories"); |
| this.repoTab= new RepoTab(this, tabItem, this.tabFolder); |
| tabItem.setControl(this.repoTab); |
| } |
| { final TabItem tabItem= new TabItem(this.tabFolder, SWT.NONE); |
| tabItem.setText("&Options"); |
| this.optionsTab= new OptionsTab(this, tabItem, this.tabFolder); |
| tabItem.setControl(this.optionsTab); |
| } |
| |
| applyDialogFont(composite); |
| |
| final DataBindingSupport databinding= new DataBindingSupport(parent); |
| addBindings(databinding); |
| |
| this.updateRepos= this.updatePkgs= this.updateState= true; |
| update(); |
| this.repoTab.init(); |
| |
| this.tabFolder.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(final SelectionEvent e) { |
| onTabSelected((TabItem) e.item); |
| } |
| }); |
| |
| return composite; |
| } |
| |
| public void activateTab(final TabItem tab) { |
| this.tabFolder.setSelection(tab); |
| onTabSelected(tab); |
| } |
| |
| private void onTabSelected(final TabItem tab) { |
| this.applyButton.setVisible(this.repoTab.getTab() == tab); |
| checkAction(); |
| } |
| |
| @Override |
| protected void createButtonsForButtonBar(final Composite parent) { |
| createButton(parent, INSTFILE_ID, "Install from file...", false); |
| createButton(parent, 99, "", false).setVisible(false); //$NON-NLS-1$ |
| this.applyButton= createButton(parent, APPLY_ID, "&Apply", false); |
| // super.createButtonsForButtonBar(parent); |
| createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true); |
| } |
| |
| private void setTabFocus() { |
| final Display display= Display.getCurrent(); |
| display.asyncExec(new Runnable() { |
| |
| @Override |
| public void run() { |
| if (display.getFocusControl() == RPkgManagerDialog.this.tabFolder) { |
| final int idx= RPkgManagerDialog.this.tabFolder.getSelectionIndex(); |
| if (idx >= 0) { |
| RPkgManagerDialog.this.tabFolder.getItem(idx).getControl().setFocus(); |
| } |
| } |
| } |
| }); |
| } |
| |
| protected void initBindings(final Control control) { |
| // databinding.installStatusListener(new StatusUpdater()); |
| } |
| |
| |
| int hintWidthInChars(final int chars) { |
| return convertWidthInCharsToPixels(chars); |
| } |
| |
| void openPrefPage(final String pageId) { |
| final Control content= getContents(); |
| final PreferenceDialog dialog= org.eclipse.ui.dialogs.PreferencesUtil |
| .createPreferenceDialogOn((content != null) ? content.getShell() : null, |
| pageId, null, null); |
| dialog.open(); |
| if (content != null) { |
| content.setFocus(); |
| } |
| } |
| |
| |
| protected void addBindings(final DataBindingSupport db) { |
| this.repoTab.addBindings(db); |
| |
| this.pkgTab.addBinding(db); |
| } |
| |
| private void update() { |
| boolean updateRepos; |
| boolean updatePkgs; |
| boolean updateState; |
| synchronized (this.updateLock) { |
| updateRepos= this.updateRepos; |
| this.updateRepos= false; |
| updatePkgs= this.updatePkgs; |
| this.updatePkgs= false; |
| updateState= this.updateState; |
| this.updateState= false; |
| if (!updateRepos && updatePkgs && !updateState) { |
| return; |
| } |
| } |
| |
| this.rPkgManager.getReadLock().lock(); |
| try { |
| if (updateRepos) { |
| this.repoTab.updateSettings(this.rPkgManager); |
| } |
| |
| if (updatePkgs) { |
| this.pkgTab.updateSettings(this.rPkgManager); |
| checkAction(); |
| } |
| updateStatus(); |
| } |
| finally { |
| this.rPkgManager.getReadLock().unlock(); |
| } |
| } |
| |
| @Override |
| // data binding |
| public void handleChange(final ChangeEvent event) { |
| updateStatus(); |
| } |
| |
| @Override |
| // core pkg manager |
| public void handleChange(final IRPkgManager.Event event) { |
| synchronized (this.updateLock) { |
| this.updateRepos |= (event.reposChanged() > 0); |
| this.updatePkgs |= (event.pkgsChanged() > 0); |
| this.updatePkgs |= (event.viewsChanged() > 0); |
| this.updateState |= true; |
| } |
| if (!this.display.isDisposed()) { |
| this.display.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| if (UIAccess.isOkToUse(getContents())) { |
| update(); |
| } |
| } |
| }); |
| } |
| } |
| |
| private void updateStatus() { |
| if (!UIAccess.isOkToUse(getContents())) { |
| return; |
| } |
| final ISelectedRepos repoSettings= this.repoTab.createRepoSettings(); |
| final Status status= this.rPkgManager.getReposStatus(repoSettings); |
| if (status.getSeverity() > Status.OK) { |
| setStatus(StatusUtils.convert(status), this.repoTab.getTab()); |
| return; |
| } |
| setStatus(new StatusInfo(IStatus.OK, "Install and Update R Packages"), this.pkgTab.getTab()); |
| } |
| |
| private void setStatus(final IStatus status, final TabItem tab) { |
| this.status= status; |
| if (!UIAccess.isOkToUse(getButtonBar())) { |
| return; |
| } |
| StatusInfo.applyToStatusLine(this, status); |
| final boolean apply= (status.getSeverity() != IStatus.ERROR); |
| getButton(IDialogConstants.OK_ID).setEnabled(apply); |
| getButton(APPLY_ID).setEnabled(apply); |
| |
| this.pkgTab.updateStatus(status); |
| |
| if (tab != null && this.updatePage >= 0 && this.updatePage == this.tabFolder.getSelectionIndex() |
| && this.tabFolder.getItem(this.updatePage) != tab) { |
| activateTab(tab); |
| } |
| this.updatePage= -1; |
| } |
| |
| protected final IStatus getStatus() { |
| return this.status; |
| } |
| |
| @Override |
| protected void buttonPressed(final int buttonId) { |
| switch (buttonId) { |
| case APPLY_ID: |
| doApply(true); |
| break; |
| case INSTFILE_ID: |
| doInstFile(); |
| break; |
| } |
| super.buttonPressed(buttonId); |
| } |
| |
| void doApply(final boolean forceRefresh) { |
| this.rPkgManager.getWriteLock().lock(); |
| try { |
| final ISelectedRepos repoSettings= this.repoTab.createRepoSettings(); |
| this.rPkgManager.setSelectedRepos(repoSettings); |
| if (forceRefresh) { |
| this.rPkgManager.request(RPkgManager.REFRESH_AVAILABLE_PKGS | RPkgManager.REFRESH_INSTALLED_PKGS); |
| } |
| |
| final int page= this.tabFolder.getSelectionIndex(); |
| this.display.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| RPkgManagerDialog.this.updatePage= page; |
| } |
| }); |
| this.rPkgManager.apply(getTool()); |
| } |
| finally { |
| this.rPkgManager.getWriteLock().unlock(); |
| } |
| } |
| |
| void doInstFile() { |
| final IREnvConfiguration config= this.rPkgManager.getREnv().get(IREnvConfiguration.class); |
| if (config == null) { |
| return; |
| } |
| final InstallPkgFileWizard wizard= new InstallPkgFileWizard(getTool(), this.rPkgManager); |
| final WizardDialog dialog= new WizardDialog(getShell(), wizard); |
| dialog.setBlockOnOpen(true); |
| dialog.open(); |
| } |
| |
| @Override |
| protected void okPressed() { |
| doApply(false); |
| super.okPressed(); |
| } |
| |
| public void start(final StartAction action) { |
| this.startAction= action; |
| if (this.pkgTab != null && this.tabFolder.getSelectionIndex() >= 0) { |
| checkAction(); |
| } |
| } |
| |
| private void checkAction() { |
| if (this.startAction != null) { |
| if (this.status.getSeverity() == IStatus.OK |
| && this.pkgTab.getPkgSet() != IRPkgSet.DUMMY) { |
| final StartAction action= this.startAction; |
| this.startAction= null; |
| switch (action.getAction()) { |
| case StartAction.INSTALL: |
| this.pkgTab.install(action.getPkgNames()); |
| break; |
| case StartAction.REINSTALL: |
| this.pkgTab.reinstallAll(); |
| break; |
| } |
| } |
| } |
| } |
| |
| } |