| /*=============================================================================# |
| # 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 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.Nullable; |
| 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.RCharacterStore; |
| import org.eclipse.statet.rj.data.RDataUtils; |
| import org.eclipse.statet.rj.data.RObject; |
| import org.eclipse.statet.rj.data.UnexpectedRDataException; |
| import org.eclipse.statet.rj.data.impl.RCharacter32Store; |
| import org.eclipse.statet.rj.services.FunctionCall; |
| import org.eclipse.statet.rj.ts.core.RToolService; |
| |
| |
| public class TextVariableFilter extends VariableFilter { |
| |
| |
| private TextSearchType searchType; |
| private String searchText; |
| |
| private RCharacter32Store availableValues; |
| |
| private final IObservableSet<@Nullable String> selectedValues; |
| |
| |
| public TextVariableFilter(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.TEXT; |
| } |
| |
| @Override |
| public void load(final VariableFilter filter) { |
| if (filter.getType() == FilterType.LEVEL) { |
| final LevelVariableFilter levelFilter= (LevelVariableFilter) filter; |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| TextVariableFilter.this.selectedValues.addAll(levelFilter.getSelectedValues()); |
| } |
| }); |
| } |
| else if (filter.getType() == FilterType.TEXT) { |
| final TextVariableFilter textFilter= (TextVariableFilter) filter; |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| if (TextVariableFilter.this.availableValues.getLength() == 0) { |
| TextVariableFilter.this.availableValues= textFilter.availableValues; |
| } |
| TextVariableFilter.this.selectedValues.addAll(textFilter.getSelectedValues()); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void reset() { |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| TextVariableFilter.this.selectedValues.clear(); |
| } |
| }); |
| } |
| |
| @Override |
| protected void update(final RToolService r, final ProgressMonitor m) throws StatusException, UnexpectedRDataException { |
| final RDataTableColumn column= getColumn(); |
| TextSearchType searchType; |
| String searchText; |
| synchronized (this) { |
| searchText= this.searchText; |
| searchType= this.searchType; |
| this.searchText= null; |
| this.searchType= null; |
| } |
| if (searchType != null && searchText != null) { |
| final FunctionCall fcall= r.createFunctionCall("rj:::.searchDataTextValues"); //$NON-NLS-1$ |
| fcall.add(column.getRExpression()); |
| fcall.addInt("type", searchType.getId()); //$NON-NLS-1$ |
| fcall.addChar("pattern", searchText); //$NON-NLS-1$ |
| fcall.addInt("max", 100); //$NON-NLS-1$ |
| |
| final RObject data= fcall.evalData(m); |
| if (data.getRObjectType() == RObject.TYPE_NULL) { |
| setError(Messages.TextFilter_TooMuch_message); |
| return; |
| } |
| addValues(RDataUtils.checkRCharVector(data).getData()); |
| } |
| } |
| |
| private static RCharacter32Store combine(final RCharacter32Store old, final RCharacterStore add) { |
| if (add.getLength() == 0) { |
| return old; |
| } |
| if (old.getLength() == 0 && add instanceof RCharacter32Store) { |
| return (RCharacter32Store) add; |
| } |
| final String[] values= new String[(int) Math.max(old.getLength() + add.getLength(), 10000)]; |
| int i= 0; |
| for (; i < add.getLength(); i++) { |
| values[i]= add.get(i); |
| } |
| for (int j= 0; j < add.getLength() && i < values.length; j++) { |
| final String s= add.get(i); |
| if (!add.contains(s)) { |
| values[i++]= s; |
| } |
| } |
| return new RCharacter32Store(values, i); |
| } |
| |
| @Override |
| protected void setError(final String message) { |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| TextVariableFilter.super.setError(message); |
| notifyListeners(); |
| } |
| }); |
| } |
| |
| protected void addValues(final RCharacterStore add) { |
| runInRealm(new Runnable() { |
| @Override |
| public void run() { |
| TextVariableFilter.this.availableValues= combine(TextVariableFilter.this.availableValues, add); |
| TextVariableFilter.super.setError(null); |
| notifyListeners(); |
| } |
| }); |
| } |
| |
| @Override |
| protected String createFilter(final String varExpression) { |
| return LevelVariableFilter.createLevelFilter(this.availableValues, this.selectedValues, varExpression); |
| } |
| |
| |
| public void search(final TextSearchType type, final String text) { |
| synchronized (this) { |
| this.searchType= type; |
| this.searchText= text; |
| } |
| scheduleUpdate(); |
| } |
| |
| public RCharacterStore getAvailableValues() { |
| return this.availableValues; |
| } |
| |
| public IObservableSet<@Nullable String> getSelectedValues() { |
| return this.selectedValues; |
| } |
| |
| public void removeAllValues() { |
| this.availableValues= NO_VALUES; |
| this.selectedValues.clear(); |
| } |
| |
| public void removeValues(final Collection<@Nullable String> values) { |
| if (values.isEmpty()) { |
| return; |
| } |
| for (final String value : values) { |
| final int idx= (int) this.availableValues.indexOf(value); |
| if (idx >= 0) { |
| this.availableValues.remove(idx); |
| } |
| } |
| this.selectedValues.removeAll(values); |
| } |
| |
| } |