| /*=============================================================================# |
| # 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.datafilter; |
| |
| import org.eclipse.core.databinding.observable.value.IObservableValue; |
| import org.eclipse.core.databinding.observable.value.WritableValue; |
| |
| import org.eclipse.statet.jcommons.status.ProgressMonitor; |
| import org.eclipse.statet.jcommons.status.StatusException; |
| |
| 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; |
| |
| |
| public class IntervalVariableFilter extends VariableFilter { |
| |
| |
| public static final int MIN_IDX= 0; |
| public static final int MAX_IDX= 1; |
| public static final int NA_IDX= 2; |
| |
| |
| private RStore<? extends Number> minMaxData; |
| |
| private final IObservableValue<Number> selectedLowerValue; |
| private final IObservableValue<Number> selectedUpperValue; |
| private final IObservableValue<Boolean> selectedNA; |
| |
| |
| protected IntervalVariableFilter(final FilterSet set, final RDataTableColumn column) { |
| super(set, column); |
| |
| this.selectedLowerValue= new WritableValue<>(set.getRealm()); |
| this.selectedUpperValue= new WritableValue<>(set.getRealm()); |
| this.selectedNA= new WritableValue<>(set.getRealm(), true, Boolean.TYPE); |
| registerObservable(this.selectedLowerValue); |
| registerObservable(this.selectedUpperValue); |
| registerObservable(this.selectedNA); |
| } |
| |
| |
| @Override |
| public FilterType getType() { |
| return FilterType.INTERVAL; |
| } |
| |
| @Override |
| public void load(final VariableFilter filter) { |
| if (filter.getType() == FilterType.INTERVAL |
| && filter.getColumn().getDataStore().getStoreType() == getColumn().getDataStore().getStoreType()) { |
| final IntervalVariableFilter intervalFilter= (IntervalVariableFilter) filter; |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| if (IntervalVariableFilter.this.minMaxData == null) { |
| IntervalVariableFilter.this.selectedLowerValue.setValue(intervalFilter.getSelectedLowerValue().getValue()); |
| IntervalVariableFilter.this.selectedUpperValue.setValue(intervalFilter.getSelectedUpperValue().getValue()); |
| IntervalVariableFilter.this.selectedNA.setValue(intervalFilter.getSelectedNA().getValue()); |
| } |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void reset() { |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| if (IntervalVariableFilter.this.minMaxData == null) { |
| return; |
| } |
| IntervalVariableFilter.this.selectedLowerValue.setValue(IntervalVariableFilter.this.minMaxData.get(MIN_IDX)); |
| IntervalVariableFilter.this.selectedUpperValue.setValue(IntervalVariableFilter.this.minMaxData.get(MAX_IDX)); |
| IntervalVariableFilter.this.selectedNA.setValue(Boolean.TRUE); |
| } |
| }); |
| } |
| |
| @Override |
| protected void update(final RToolService r, final ProgressMonitor m) throws StatusException, UnexpectedRDataException { |
| final RDataTableColumn column= getColumn(); |
| { final FunctionCall fcall= r.createFunctionCall("rj:::.getDataIntervalValues"); //$NON-NLS-1$ |
| fcall.add(column.getRExpression()); |
| |
| final RObject data= fcall.evalData(m); |
| RDataUtils.checkRVector(data); |
| setValues((RStore<Number>) RDataUtils.checkData(data.getData(), column.getDataStore().getStoreType())); |
| return; |
| } |
| } |
| |
| @Override |
| protected void setError(final String message) { |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| IntervalVariableFilter.this.minMaxData= null; |
| IntervalVariableFilter.super.setError(message); |
| notifyListeners(); |
| } |
| }); |
| } |
| |
| protected void setValues(final RStore<? extends Number> minMaxData) { |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| boolean wasMin; |
| { final Object value= IntervalVariableFilter.this.selectedLowerValue.getValue(); |
| wasMin= (value == null || value.equals(minMaxData.get(MIN_IDX))); |
| } |
| boolean wasMax; |
| { final Object value= IntervalVariableFilter.this.selectedLowerValue.getValue(); |
| wasMax= (value == null || value.equals(minMaxData.get(MAX_IDX))); |
| } |
| IntervalVariableFilter.this.minMaxData= minMaxData; |
| if (wasMin) { |
| IntervalVariableFilter.this.selectedLowerValue.setValue(IntervalVariableFilter.this.minMaxData.get(MIN_IDX)); |
| } |
| if (wasMax) { |
| IntervalVariableFilter.this.selectedUpperValue.setValue(IntervalVariableFilter.this.minMaxData.get(MAX_IDX)); |
| } |
| IntervalVariableFilter.super.setError(null); |
| notifyListeners(); |
| } |
| }); |
| } |
| |
| private static boolean isSmaller(final Number e1, final Number e2) { |
| if (e1 instanceof Integer) { |
| return (((Integer) e1).intValue() < ((Integer) e2).intValue()); |
| } |
| return (e1.doubleValue() < e2.doubleValue()); |
| } |
| |
| private static boolean isGreater(final Object e1, final Object e2) { |
| if (e1 instanceof Integer) { |
| return (((Integer) e1).intValue() > ((Integer) e2).intValue()); |
| } |
| return (((Number) e1).doubleValue() > ((Number) e2).doubleValue()); |
| } |
| |
| @Override |
| protected String createFilter(final String varExpression) { |
| if (this.minMaxData == null |
| || this.selectedLowerValue.getValue() == null |
| || this.selectedUpperValue.getValue() == null) { |
| return null; |
| } |
| final StringBuilder sb= new StringBuilder(); |
| sb.append('('); |
| { |
| final Number lower= this.selectedLowerValue.getValue(); |
| if (isGreater(lower, this.minMaxData.get(MIN_IDX))) { |
| sb.append(varExpression); |
| sb.append(" >= "); //$NON-NLS-1$ |
| sb.append(lower); |
| } |
| } |
| { final Number upper= this.selectedUpperValue.getValue(); |
| if (isSmaller(upper, this.minMaxData.get(MAX_IDX))) { |
| if (sb.length() > 1) { |
| sb.append(" & "); //$NON-NLS-1$ |
| } |
| sb.append(varExpression); |
| sb.append(" <= "); //$NON-NLS-1$ |
| sb.append(upper); |
| } |
| } |
| // if (this.minMaxData.getLogi(NA_IDX)) { |
| final Boolean na= (!this.minMaxData.getLogi(NA_IDX)) |
| || this.selectedNA.getValue(); |
| if (na) { |
| if (sb.length() > 1) { |
| sb.insert(0, '('); |
| sb.append(") | "); //$NON-NLS-1$ |
| sb.append("is.na(").append(varExpression).append(')'); //$NON-NLS-1$ |
| } |
| } |
| else { // !na |
| if (sb.length() > 1) { |
| sb.append(" & "); //$NON-NLS-1$ |
| } |
| sb.append("!is.na(").append(varExpression).append(')'); //$NON-NLS-1$ |
| } |
| // } |
| sb.append(')'); |
| return (sb.length() <= 2) ? "" : sb.toString(); //$NON-NLS-1$ |
| } |
| |
| |
| public RStore<? extends Number> getMinMaxData() { |
| return this.minMaxData; |
| } |
| |
| |
| public IObservableValue<Number> getSelectedLowerValue() { |
| return this.selectedLowerValue; |
| } |
| |
| public IObservableValue<Number> getSelectedUpperValue() { |
| return this.selectedUpperValue; |
| } |
| |
| public IObservableValue<Boolean> getSelectedNA() { |
| return this.selectedNA; |
| } |
| |
| } |