| /*=============================================================================# |
| # 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.datafilter; |
| |
| import java.util.Collection; |
| |
| import org.eclipse.core.databinding.observable.set.IObservableSet; |
| import org.eclipse.core.databinding.observable.set.WritableSet; |
| |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.status.ProgressMonitor; |
| import org.eclipse.statet.jcommons.status.StatusException; |
| |
| import org.eclipse.statet.r.core.RUtil; |
| import org.eclipse.statet.r.ui.dataeditor.RDataTableColumn; |
| import org.eclipse.statet.rj.data.RDataUtils; |
| import org.eclipse.statet.rj.data.RObject; |
| import org.eclipse.statet.rj.data.RStore; |
| import org.eclipse.statet.rj.data.UnexpectedRDataException; |
| import org.eclipse.statet.rj.services.FunctionCall; |
| import org.eclipse.statet.rj.ts.core.RToolService; |
| |
| |
| @NonNullByDefault |
| public class LevelVariableFilter extends VariableFilter { |
| |
| |
| private RStore<?> availableValues; |
| |
| private final IObservableSet<Object> selectedValues; |
| |
| |
| public LevelVariableFilter(final FilterSet set, final RDataTableColumn column) { |
| super(set, column); |
| |
| this.availableValues= NO_VALUES; |
| this.selectedValues= new WritableSet<>(set.getRealm()); |
| registerObservable(this.selectedValues); |
| } |
| |
| |
| @Override |
| public FilterType getType() { |
| return FilterType.LEVEL; |
| } |
| |
| @Override |
| public void load(final VariableFilter filter) { |
| if (filter.getType() == FilterType.LEVEL) { |
| final LevelVariableFilter levelFilter= (LevelVariableFilter)filter; |
| runInRealm(() -> { |
| this.selectedValues.addAll(levelFilter.getSelectedValues()); |
| }); |
| } |
| else if (filter.getType() == FilterType.TEXT) { |
| final TextVariableFilter textFilter= (TextVariableFilter)filter; |
| runInRealm(() -> { |
| this.selectedValues.addAll(textFilter.getSelectedValues()); |
| }); |
| } |
| } |
| |
| @Override |
| public void reset() { |
| runInRealm(() -> { |
| this.selectedValues.clear(); |
| }); |
| } |
| |
| @Override |
| protected void update(final RToolService r, final ProgressMonitor m) throws StatusException, UnexpectedRDataException { |
| final RDataTableColumn column= getColumn(); |
| { final FunctionCall fcall= r.createFunctionCall("rj:::.getDataLevelValues"); //$NON-NLS-1$ |
| fcall.add(column.getRExpression()); |
| fcall.addInt("max", 1000); //$NON-NLS-1$ |
| |
| final RObject data= fcall.evalData(m); |
| if (data.getRObjectType() == RObject.TYPE_NULL) { |
| setError(Messages.LevelFilter_TooMuch_message); |
| return; |
| } |
| RDataUtils.checkRVector(data); |
| if (column.getDataStore().getStoreType() == RStore.FACTOR) { |
| setValues(RDataUtils.checkData(data.getData(), RStore.CHARACTER)); |
| } |
| else { |
| setValues(RDataUtils.checkData(data.getData(), column.getDataStore().getStoreType())); |
| } |
| return; |
| } |
| } |
| |
| @Override |
| protected void setError(final String message) { |
| runInRealm(() -> { |
| this.availableValues= NO_VALUES; |
| doSetError(message); |
| notifyListeners(); |
| }); |
| } |
| |
| protected void setValues(final RStore<?> values) { |
| runInRealm(() -> { |
| if (!this.availableValues.equals(values) || getError() != null) { |
| this.availableValues= values; |
| clearError(); |
| notifyListeners(); |
| } |
| }); |
| } |
| |
| |
| @Override |
| protected @Nullable String createFilter(final String varExpression) { |
| return createLevelFilter(this.availableValues, this.selectedValues, varExpression); |
| } |
| |
| static @Nullable String createLevelFilter(final @Nullable RStore<?> availableValues, |
| final Collection<?> selectedValues, final String varExpression) { |
| if (availableValues == null) { |
| return null; |
| } |
| final StringBuilder sb= new StringBuilder(); |
| sb.append('('); |
| int num= 0; |
| int na= 0; |
| for (int i= 0; i < availableValues.getLength(); i++) { |
| final Object element= availableValues.get(i); |
| if (element == null) { |
| na= (selectedValues.contains(element)) ? 1 : -1; |
| continue; |
| } |
| if (selectedValues.contains(element)) { |
| if (num > 0) { |
| sb.append(" | "); //$NON-NLS-1$ |
| } |
| sb.append(varExpression); |
| sb.append(" == "); //$NON-NLS-1$ |
| if (element instanceof String) { |
| sb.append('"').append(RUtil.escapeCompletely((String)element)).append('"'); |
| } |
| else { |
| sb.append(element); |
| } |
| num++; |
| } |
| } |
| if (num > 0 || na == 1) { |
| if (na >= 0) { |
| if (num > 0) { |
| sb.append(" | "); //$NON-NLS-1$ |
| } |
| sb.append("is.na(").append(varExpression).append(')'); //$NON-NLS-1$ |
| } |
| else { |
| if (num > 0) { |
| sb.insert(0, '('); |
| sb.append(')'); |
| sb.append(" & "); //$NON-NLS-1$ |
| } |
| sb.append("!is.na(").append(varExpression).append(')'); //$NON-NLS-1$ |
| } |
| if (na == 1) { |
| num++; |
| } |
| } |
| sb.append(')'); |
| return (sb.length() <= 2 || num == availableValues.getLength()) ? "" : sb.toString(); //$NON-NLS-1$ |
| } |
| |
| |
| public RStore<?> getAvailableValues() { |
| return this.availableValues; |
| } |
| |
| public IObservableSet getSelectedValues() { |
| return this.selectedValues; |
| } |
| |
| } |