blob: 3dec2fc5b3149cecb4b5e50c0f59640bf1e950e3 [file] [log] [blame]
/*=============================================================================#
# 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);
}
}