| /*=============================================================================# |
| # Copyright (c) 2012, 2019 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 static org.eclipse.statet.jcommons.lang.ObjectUtils.NonNull_Object_TYPE; |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.NonNull_String_TYPE; |
| import static org.eclipse.statet.jcommons.lang.ObjectUtils.Nullable_Object_TYPE; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.databinding.DataBindingContext; |
| import org.eclipse.core.databinding.UpdateValueStrategy; |
| import org.eclipse.core.databinding.beans.typed.PojoProperties; |
| import org.eclipse.core.databinding.observable.list.IObservableList; |
| import org.eclipse.core.databinding.observable.list.WritableList; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.jface.databinding.swt.typed.WidgetProperties; |
| import org.eclipse.jface.databinding.viewers.typed.ViewerProperties; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.viewers.ArrayContentProvider; |
| import org.eclipse.jface.viewers.ColumnWeightData; |
| import org.eclipse.jface.viewers.ComboViewer; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TableViewerColumn; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImList; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.ecommons.databinding.NotEmptyValidator; |
| import org.eclipse.statet.ecommons.databinding.URLValidator; |
| import org.eclipse.statet.ecommons.databinding.core.conversion.ClassTypedConverter; |
| import org.eclipse.statet.ecommons.databinding.jface.DataBindingSupport; |
| import org.eclipse.statet.ecommons.preferences.core.Preference; |
| import org.eclipse.statet.ecommons.preferences.ui.ConfigurationBlock; |
| import org.eclipse.statet.ecommons.preferences.ui.ConfigurationBlockPreferencePage; |
| import org.eclipse.statet.ecommons.preferences.ui.ManagedConfigurationBlock; |
| import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener; |
| import org.eclipse.statet.ecommons.ui.components.ButtonGroup; |
| import org.eclipse.statet.ecommons.ui.components.ButtonGroup.IActions; |
| import org.eclipse.statet.ecommons.ui.dialogs.ExtStatusDialog; |
| import org.eclipse.statet.ecommons.ui.util.LayoutUtils; |
| import org.eclipse.statet.ecommons.ui.viewers.ComparatorViewerComparator; |
| import org.eclipse.statet.ecommons.ui.viewers.ViewerUtils; |
| import org.eclipse.statet.ecommons.ui.viewers.ViewerUtils.TableComposite; |
| |
| import org.eclipse.statet.r.core.pkgmanager.IRPkgManager; |
| import org.eclipse.statet.r.core.pkgmanager.RRepo; |
| import org.eclipse.statet.rj.renv.core.RPkgType; |
| |
| |
| @NonNullByDefault |
| public class RRepoPreferencePage extends ConfigurationBlockPreferencePage { |
| |
| |
| public RRepoPreferencePage() { |
| } |
| |
| |
| @Override |
| protected ConfigurationBlock createConfigurationBlock() throws CoreException { |
| return new RRepoConfigurationBlock(createStatusChangedListener()); |
| } |
| |
| } |
| |
| |
| @NonNullByDefault |
| class EditRepoDialog extends ExtStatusDialog { |
| |
| |
| private static final String DEFAULT_TYPE= "Default"; //$NON-NLS-1$ |
| |
| @SuppressWarnings("null") |
| private static final Class<@Nullable RPkgType> Nullable_RPkgType_TYPE= RPkgType.class; |
| |
| |
| private final RRepo repo; |
| private final boolean isNew; |
| |
| private Text nameControl; |
| private Text urlControl; |
| private ComboViewer typeControl; |
| |
| |
| public EditRepoDialog(final Shell parent, final RRepo repo, final boolean isNew) { |
| super(parent, (isNew) ? WITH_DATABINDING_CONTEXT : |
| (WITH_DATABINDING_CONTEXT | SHOW_INITIAL_STATUS)); |
| this.repo= repo; |
| this.isNew= isNew; |
| |
| setTitle(isNew ? "Add Repository" : "Edit Repository"); |
| } |
| |
| |
| @Override |
| protected Control createDialogArea(final Composite parent) { |
| final Composite area= new Composite(parent, SWT.NONE); |
| area.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| area.setLayout(LayoutUtils.newDialogGrid(2)); |
| |
| { final Label label= new Label(area, SWT.NONE); |
| label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); |
| label.setText("Name:"); |
| } |
| { final Text text= new Text(area, SWT.BORDER); |
| text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| this.nameControl= text; |
| } |
| { final Label label= new Label(area, SWT.NONE); |
| label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); |
| label.setText("URL:"); |
| } |
| { final Text text= new Text(area, SWT.BORDER); |
| final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false); |
| gd.widthHint= LayoutUtils.hintWidth(this.nameControl, 60); |
| text.setLayoutData(gd); |
| this.urlControl= text; |
| } |
| { final Label label= new Label(area, SWT.NONE); |
| label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); |
| label.setText("Type:"); |
| } |
| { final ComboViewer viewer= new ComboViewer(area, SWT.READ_ONLY | SWT.BORDER | SWT.DROP_DOWN); |
| final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, true, false); |
| gd.widthHint= LayoutUtils.hintWidth(viewer.getCombo(), 10); |
| viewer.getCombo().setLayoutData(gd); |
| viewer.setContentProvider(ArrayContentProvider.getInstance()); |
| viewer.setLabelProvider(new LabelProvider() { |
| @Override |
| public String getText(final Object element) { |
| if (element instanceof RPkgType) { |
| return ((RPkgType) element).getLabel(); |
| } |
| return super.getText(element); |
| } |
| }); |
| viewer.setInput(new Object[] { |
| DEFAULT_TYPE, RPkgType.SOURCE, RPkgType.BINARY |
| }); |
| viewer.setSelection(new StructuredSelection(DEFAULT_TYPE)); |
| this.typeControl= viewer; |
| } |
| |
| LayoutUtils.addSmallFiller(area, true); |
| |
| applyDialogFont(area); |
| |
| return area; |
| } |
| |
| @Override |
| protected void addBindings(final DataBindingSupport databinding) { |
| final DataBindingContext dbc= databinding.getContext(); |
| dbc.bindValue( |
| WidgetProperties.text(SWT.Modify) |
| .observe(this.nameControl), |
| PojoProperties.value(RRepo.class, "name", NonNull_String_TYPE) //$NON-NLS-1$ |
| .observe(this.repo), |
| null, |
| null ); |
| dbc.bindValue( |
| WidgetProperties.text(SWT.Modify) |
| .observe(this.urlControl), |
| PojoProperties.value(RRepo.class, "URL", NonNull_String_TYPE) //$NON-NLS-1$ |
| .observe(this.repo), |
| new UpdateValueStrategy<String, String>() |
| .setAfterGetValidator( |
| new NotEmptyValidator("URL", new URLValidator("URL")) ), |
| null ); |
| dbc.bindValue( |
| ViewerProperties.singleSelection(Object.class) |
| .observe(this.typeControl), |
| PojoProperties.value(RRepo.class, "pkgType", Nullable_RPkgType_TYPE) //$NON-NLS-1$ |
| .observe(this.repo), |
| new UpdateValueStrategy<@Nullable Object, @Nullable RPkgType>() |
| .setConverter(ClassTypedConverter.create(Nullable_Object_TYPE, Nullable_RPkgType_TYPE, |
| (final @Nullable Object fromObject) -> |
| (fromObject != DEFAULT_TYPE) ? (RPkgType)fromObject : null )), |
| new UpdateValueStrategy<@Nullable RPkgType, @Nullable Object>() |
| .setConverter(ClassTypedConverter.create(Nullable_RPkgType_TYPE, NonNull_Object_TYPE, |
| (final @Nullable RPkgType fromObject) -> |
| (fromObject != null) ? fromObject : DEFAULT_TYPE ))); |
| } |
| |
| } |
| |
| class RRepoConfigurationBlock extends ManagedConfigurationBlock implements IActions<RRepo> { |
| |
| |
| private static final int R_SIZE= 3; |
| |
| private static final int REPO= 0; |
| private static final int CRAN= 1; |
| private static final int BIOC= 2; |
| |
| private static final ImList<Preference<List<RRepo>>> PREFS= ImCollections.newList( |
| IRPkgManager.CUSTOM_REPO_PREF, |
| IRPkgManager.CUSTOM_CRAN_MIRROR_PREF, |
| IRPkgManager.CUSTOM_BIOC_MIRROR_PREF ); |
| |
| private static final Comparator<RRepo> COMPARATOR= new Comparator<RRepo>() { |
| |
| @Override |
| public int compare(final RRepo o1, final RRepo o2) { |
| final int diff= o1.getName().compareTo(o2.getName()); |
| if (diff != 0) { |
| return diff; |
| } |
| return o1.getId().compareTo(o2.getId()); |
| } |
| |
| }; |
| |
| |
| private final TableComposite[] tables= new TableComposite[R_SIZE]; |
| @SuppressWarnings("unchecked") |
| private final ButtonGroup<RRepo>[] buttonsGroups= new ButtonGroup[R_SIZE]; |
| |
| @SuppressWarnings("unchecked") |
| private final IObservableList<RRepo>[] lists= new IObservableList[R_SIZE]; |
| |
| private final Set<String> ids= new HashSet<>(); |
| |
| |
| public RRepoConfigurationBlock(final StatusChangeListener statusListener) { |
| super(null, "R Custom Repositories", statusListener); |
| } |
| |
| |
| @Override |
| protected void createBlockArea(final Composite pageComposite) { |
| final Map<Preference<?>, String> prefs= new HashMap<>(); |
| |
| prefs.put(IRPkgManager.CUSTOM_REPO_PREF, null); |
| prefs.put(IRPkgManager.CUSTOM_CRAN_MIRROR_PREF, null); |
| prefs.put(IRPkgManager.CUSTOM_BIOC_MIRROR_PREF, null); |
| |
| setupPreferenceManager(prefs); |
| |
| addLinkHeader(pageComposite, "Additional custom repositories for R packages. " + |
| "There is no need to add the default R repositories or mirrors."); |
| |
| final Composite composite= new Composite(pageComposite, SWT.NONE); |
| composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| composite.setLayout(LayoutUtils.newCompositeGrid(2)); |
| |
| createTable(composite, REPO, "R&epositories"); |
| createTable(composite, CRAN, "CR&AN Mirrors"); |
| createTable(composite, BIOC, "&Bioconductor Mirrors"); |
| |
| initBindings(); |
| |
| updateControls(); |
| } |
| |
| @Override |
| protected void addBindings(final DataBindingSupport db) { |
| for (int i= 0; i < R_SIZE; i++) { |
| this.lists[i]= new WritableList<>(db.getRealm(), new ArrayList<RRepo>(), RRepo.class); |
| this.tables[i].viewer.setContentProvider(new ArrayContentProvider()); |
| this.tables[i].viewer.setInput(this.lists[i]); |
| this.buttonsGroups[i].connectTo(this.tables[i].viewer, this.lists[i], null); |
| } |
| } |
| |
| |
| private void createTable(final Composite parent, final int r, final String s) { |
| { final Label label= new Label(parent, SWT.NONE); |
| label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); |
| label.setText(s+':'); |
| } |
| { final TableComposite table= new TableComposite(parent, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); |
| // table.table.setHeaderVisible(true); |
| { final GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1); |
| gd.heightHint= LayoutUtils.hintHeight(table.table, (r == REPO) ? 9 : 3); |
| table.setLayoutData(gd); |
| } |
| { final TableViewerColumn column= table.addColumn("Repository", SWT.LEFT, new ColumnWeightData(100)); |
| column.setLabelProvider(new RRepoLabelProvider()); |
| } |
| // { final TableViewerColumn column= table.addColumn("Name", SWT.LEFT, new ColumnWeightData(40)); |
| // column.setLabelProvider(new RepoLabelProvider()); |
| // } |
| // { final TableViewerColumn column= table.addColumn("URL", SWT.LEFT, new ColumnWeightData(60)); |
| // column.setLabelProvider(new RepoLabelProvider()); |
| // } |
| table.viewer.setComparator(new ComparatorViewerComparator(COMPARATOR)); |
| this.tables[r]= table; |
| |
| ViewerUtils.scheduleStandardSelection(table.viewer); |
| } |
| { final ButtonGroup<RRepo> buttons= new ButtonGroup<>(parent, this, false); |
| buttons.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, 1, 1)); |
| |
| buttons.addAddButton(null); |
| buttons.addEditButton(null); |
| buttons.addDeleteButton(null); |
| |
| this.buttonsGroups[r]= buttons; |
| } |
| } |
| |
| @Override |
| public RRepo edit(final int command, final RRepo item, final Object parent) { |
| final RRepo repo= new RRepo(((command & ButtonGroup.ADD_ANY) != 0) ? newId() : item.getId()); |
| if (item != null) { |
| repo.set(item); |
| } |
| final Dialog dialog= new EditRepoDialog(getShell(), repo, item == null); |
| if (dialog.open() == Dialog.OK) { |
| if (repo.getName().isEmpty()) { |
| repo.setName(RRepo.hintName(repo)); |
| } |
| return repo; |
| } |
| return null; |
| } |
| |
| private String newId() { |
| String id; |
| do { |
| id= RRepo.CUSTOM_PREFIX + System.currentTimeMillis(); |
| } |
| while (this.ids.contains(id)); |
| return id; |
| } |
| |
| @Override |
| public void updateState(final IStructuredSelection selection) { |
| } |
| |
| @Override |
| protected void updateControls() { |
| super.updateControls(); |
| for (int i= 0; i < R_SIZE; i++) { |
| this.lists[i].clear(); |
| final List<RRepo> repos= getPreferenceValue(PREFS.get(i)); |
| for (final RRepo repo : repos) { |
| this.ids.add(repo.getId()); |
| } |
| this.lists[i].addAll(repos); |
| this.buttonsGroups[i].refresh(); |
| } |
| } |
| |
| @Override |
| protected void updatePreferences() { |
| for (int i= 0; i < R_SIZE; i++) { |
| final RRepo[] array= this.lists[i].toArray(new RRepo[this.lists[i].size()]); |
| Arrays.sort(array, COMPARATOR); |
| setPrefValue(PREFS.get(i), ImCollections.newList(array)); |
| } |
| super.updatePreferences(); |
| } |
| |
| } |