Skip to content

Commit ad95625

Browse files
committed
make filtertext better and translateable as mentioned here: jasp-stats/jasp-issues#2515 (comment)
ctrl/cmd+enter should run r code also adds is.na to constructors just replace the DEFAULT_FILTER define with the correct function calls and see what happens make filter error show up again... fix statusbar jasp-stats/INTERNAL-jasp#2462 slightly less computersciency tooltip
1 parent 17b0f4b commit ad95625

File tree

13 files changed

+91
-44
lines changed

13 files changed

+91
-44
lines changed

CommonData/filter.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
#include <vector>
77
#include "utils.h"
88

9-
#define DEFAULT_FILTER "# Add filters using R syntax here, see info button for help.\n\ngeneratedFilter # by default: pass the non-R filter(s)"
109
#define DEFAULT_FILTER_JSON "{\"formulas\":[]}"
1110
#define DEFAULT_FILTER_GEN "generatedFilter <- rep(TRUE, rowcount)"
1211

12+
1313
class DataSet;
1414
class DatabaseInterface;
1515

@@ -61,9 +61,9 @@ class Filter : public DataSetBaseNode
6161
DataSet * _data = nullptr;
6262
int _id = -1,
6363
_filteredRowCount = 0;
64-
std::string _rFilter = DEFAULT_FILTER,
65-
_generatedFilter = DEFAULT_FILTER_GEN,
66-
_constructorJson = DEFAULT_FILTER_JSON,
64+
std::string _rFilter = "",
65+
_generatedFilter = "",
66+
_constructorJson = "",
6767
_constructorR = "",
6868
_errorMsg = "";
6969
std::vector<bool> _filtered;

Desktop/components/JASP/Widgets/ComputeColumnWindow.qml

+12
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ FocusScope
121121
property bool changed: text != computedColumnsInterface.computeColumnRCode
122122

123123
KeyNavigation.tab: applyComputedColumnButton
124+
125+
126+
Keys.onReturnPressed: (keyEvent) => {
127+
if(keyEvent.modifiers & Qt.ControlModifier)
128+
{
129+
if(changedSinceLastApply)
130+
computedColumnContainer.applyComputedColumn()
131+
}
132+
else
133+
keyEvent.accepted = false
134+
}
124135
}
125136

126137

@@ -190,6 +201,7 @@ FocusScope
190201
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "replaceNA"; functionParameters: "column,replaceWith"; functionParamTypes: "string:boolean:number,string:boolean:number"; toolTip: qsTr("replace any missing values (NA) in column by the value in replaceWith") }
191202
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "ifElse"; functionParameters: "test,then,else"; functionParamTypes: "boolean,boolean:string:number,boolean:string:number"; toolTip: qsTr("if-else statement") }
192203
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "hasSubstring"; functionParameters: "string,substring"; functionParamTypes: "string,string"; toolTip: qsTr("returns true if string contains substring at least once") }
204+
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "is.na"; functionParameters: "y"; functionParamTypes: "string:number:boolean"; toolTip: qsTr("returns a boolean vector with TRUE for each missing value in y") }
193205

194206
ListElement { type: "separator" }
195207
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "normalDist"; functionParameters: "mean,sd"; functionParamTypes: "number,number"; toolTip: qsTr("generates data from a Gaussian distribution with specified mean and standard deviation sd") }

Desktop/components/JASP/Widgets/FilterConstructor/DropSpot.qml

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ DropArea {
5656
return false
5757
}
5858

59-
onEntered:
59+
onEntered: (drag)=>
6060
{
6161
//console.log(__debugName," onEntered DROPSPOT")
6262

Desktop/components/JASP/Widgets/FilterConstructor/FilterConstructor.qml

+1-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ Item
242242
MouseArea
243243
{
244244
anchors.fill: parent
245-
onPressed: { scriptColumn.focus = true; mouse.accepted = false; }
245+
onPressed: (mouse) => { scriptColumn.focus = true; mouse.accepted = false; }
246246
}
247247

248248
DropTrash

Desktop/components/JASP/Widgets/FilterConstructor/Function.qml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Item
1818
property variant functionNameToImageSource: { "sum": jaspTheme.iconPath + "/sum.png", "prod": jaspTheme.iconPath + "/product.png", "sd": jaspTheme.iconPath + "/sigma.png", "var": jaspTheme.iconPath + "/variance.png", "!": jaspTheme.iconPath + "/negative.png", "sqrt":jaspTheme.iconPath + "/rootHead.png"}
1919
property string functionImageSource: functionNameToImageSource[functionName] !== undefined ? functionNameToImageSource[functionName] : ""
2020
property bool isNested: false
21-
property var booleanReturningFunctions: ["!", "hasSubstring"]
21+
property var booleanReturningFunctions: ["!", "hasSubstring", "is.na"]
2222

2323
readonly property bool isIfElse: functionName === "ifelse"
2424
property var ifElseReturn: ["string", "number", "boolean"]

Desktop/components/JASP/Widgets/FilterWindow.qml

+11
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ FocusScope
128128
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "median"; functionParameters: "values"; functionParamTypes: "number"; toolTip: qsTr("median") }
129129
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "ifelse"; functionParameters: "test,then,else"; functionParamTypes: "boolean,boolean:string:number,boolean:string:number"; toolTip: qsTr("if-else statement") }
130130
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "hasSubstring"; functionParameters: "string,substring"; functionParamTypes: "string,string"; toolTip: qsTr("returns true if string contains substring at least once") }
131+
ListElement { type: "function"; friendlyFunctionName: ""; functionName: "is.na"; functionParameters: "y"; functionParamTypes: "string:number:boolean"; toolTip: qsTr("Combine with not-operator to filter out rows with missing values (NA) for a column.") }
131132
}
132133

133134
function askIfChanged(closeFunc)
@@ -358,6 +359,16 @@ FocusScope
358359

359360
property bool changedSinceLastApply: text !== filterModel.rFilter
360361

362+
Keys.onReturnPressed: (keyEvent) => {
363+
if(keyEvent.modifiers & Qt.ControlModifier)
364+
{
365+
if(filterEdit.changedSinceLastApply)
366+
filterWindow.applyAndSendFilter(filterEdit.text)
367+
}
368+
else
369+
keyEvent.accepted = false
370+
}
371+
361372
anchors
362373
{
363374
top: parent.top

Desktop/data/filtermodel.cpp

+17-9
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,22 @@ QString FilterModel::filterErrorMsg() const { return !DataSetPackage::filter() ?
1919
QString FilterModel::generatedFilter() const { return !DataSetPackage::filter() ? "" : tq(DataSetPackage::filter()->generatedFilter()); }
2020
QString FilterModel::constructorJson() const { return !DataSetPackage::filter() ? "" : tq(DataSetPackage::filter()->constructorJson()); }
2121

22+
const char * FilterModel::defaultRFilter()
23+
{
24+
static std::string defaultFilter;
25+
defaultFilter = tr( "# Add filters using R syntax here. By default the non-R filter(s) are passed with generatedFilter." "\n"
26+
"# To include generated filters, append clauses with \"&\": generatedFilter & ..." "\n"
27+
"# Click the (i) icon in the lower right corner for further help." "\n\n"
28+
"generatedFilter" ).toStdString();
29+
30+
return defaultFilter.c_str();
31+
}
32+
2233
void FilterModel::reset()
2334
{
2435
_setGeneratedFilter(DEFAULT_FILTER_GEN );
2536
setConstructorJson( DEFAULT_FILTER_JSON );
26-
_setRFilter( DEFAULT_FILTER );
37+
_setRFilter( defaultRFilter() );
2738

2839
if(DataSetPackage::pkg()->rowCount() > 0)
2940
sendGeneratedAndRFilter();
@@ -191,19 +202,16 @@ void FilterModel::updateStatusBar()
191202
{
192203
if(!DataSetPackage::pkg()->hasDataSet())
193204
{
194-
setStatusBarText("No data loaded!");
205+
setStatusBarText(tr("No data loaded!"));
195206
return;
196207
}
197208

198-
int TotalCount = DataSetPackage::pkg()->rowCount(),
209+
int TotalCount = DataSetPackage::pkg()->dataRowCount(),
199210
TotalThroughFilter = DataSetPackage::pkg()->filteredRowCount();
200-
double PercentageThrough = 100.0 * ((double)TotalThroughFilter) / ((double)TotalCount);
201-
202-
std::stringstream ss;
203-
if(hasFilter())
204-
ss << "Data has " << TotalCount << " rows, " << TotalThroughFilter << " (~" << (int)round(PercentageThrough) << "%) passed through filter";
211+
int PercentageThrough = (int)round(100.0 * ((double)TotalThroughFilter) / ((double)TotalCount));
212+
bool Approximate = PercentageThrough != TotalThroughFilter;
205213

206-
setStatusBarText(tq(ss.str()));
214+
setStatusBarText(tr("Data has %1 rows, %2 (%3%4%) passed through filter").arg(TotalCount).arg(TotalThroughFilter).arg(Approximate ? "~" : "").arg(PercentageThrough));
207215
}
208216

209217
void FilterModel::rescanRFilterForColumns()

Desktop/data/filtermodel.h

+15-16
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#include <QObject>
55
#include "utilities/qutils.h"
6-
#include "datasetpackage.h"
76
#include "labelfiltergenerator.h"
87

98
///
@@ -22,27 +21,27 @@ class FilterModel : public QObject
2221
Q_PROPERTY( QString defaultRFilter READ defaultRFilter NOTIFY defaultRFilterChanged )
2322

2423
public:
25-
explicit FilterModel(labelFilterGenerator * labelfilterGenerator);
24+
explicit FilterModel(labelFilterGenerator * labelfilterGenerator);
2625

27-
void init();
26+
void init();
2827

29-
QString rFilter() const;
30-
QString constructorR() const;
31-
QString statusBarText() const { return _statusBarText; }
32-
QString filterErrorMsg() const;
33-
QString generatedFilter() const;
34-
QString constructorJson() const;
35-
QString defaultRFilter() const { return DEFAULT_FILTER; }
28+
QString rFilter() const;
29+
QString constructorR() const;
30+
QString statusBarText() const { return _statusBarText; }
31+
QString filterErrorMsg() const;
32+
QString generatedFilter() const;
33+
QString constructorJson() const;
34+
static const char * defaultRFilter();
3635

37-
bool hasFilter() const { return rFilter() != DEFAULT_FILTER || constructorJson() != DEFAULT_FILTER_JSON; }
36+
bool hasFilter() const { return rFilter() != defaultRFilter() || constructorJson() != DEFAULT_FILTER_JSON; }
3837

3938

40-
Q_INVOKABLE void resetRFilter() { applyRFilter(DEFAULT_FILTER); }
41-
void sendGeneratedAndRFilter();
39+
Q_INVOKABLE void resetRFilter() { applyRFilter(defaultRFilter()); }
40+
void sendGeneratedAndRFilter();
4241

43-
void updateStatusBar();
44-
void reset();
45-
void modelInit();
42+
void updateStatusBar();
43+
void reset();
44+
void modelInit();
4645

4746
public slots:
4847
GENERIC_SET_FUNCTION(StatusBarText, _statusBarText, statusBarTextChanged, QString)

Desktop/data/importers/jaspimporterold.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
//
1717

1818
#include "jaspimporterold.h"
19-
#include "columnutils.h"
19+
#include "data/filtermodel.h"
2020
#include <fstream>
2121

2222
#include <sys/stat.h>
@@ -106,7 +106,7 @@ void JASPImporterOld::loadDataArchive_1_00(const std::string &path, std::functio
106106

107107
packageData->dataSet()->setDataFileSynch(true);
108108

109-
DataSetPackage::filter()->setRFilter( metaData.get("filterData", DEFAULT_FILTER) .asString());
109+
DataSetPackage::filter()->setRFilter( metaData.get("filterData", FilterModel::defaultRFilter()) .asString());
110110

111111
Json::Value jsonFilterConstructor = metaData.get("filterConstructorJSON", DEFAULT_FILTER_JSON);
112112
DataSetPackage::filter()->setConstructorJson(jsonFilterConstructor.isObject() ? jsonFilterConstructor.toStyledString() : jsonFilterConstructor.asString());
@@ -229,8 +229,8 @@ void JASPImporterOld::loadDataArchive_1_00(const std::string &path, std::functio
229229
//Filter should be run if filterVector was not filled and either of the filters was different from default.
230230
bool filterShouldBeRun =
231231
filterVector.size() == 0 &&
232-
( metaData.get("filterData", DEFAULT_FILTER).asString() != DEFAULT_FILTER
233-
|| metaData.get("filterConstructorJSON", DEFAULT_FILTER_JSON).asString() != DEFAULT_FILTER_JSON );
232+
( metaData.get("filterData", FilterModel::defaultRFilter()).asString() != FilterModel::defaultRFilter()
233+
|| metaData.get("filterConstructorJSON", DEFAULT_FILTER_JSON).asString() != DEFAULT_FILTER_JSON );
234234

235235
packageData->setFilterShouldRunInit(filterShouldBeRun);
236236
}

Desktop/data/labelfiltergenerator.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "labelfiltergenerator.h"
2+
#include "filtermodel.h"
23

34
labelFilterGenerator::labelFilterGenerator(ColumnModel *columnModel, QObject *parent)
45
: QObject(parent), _columnModel(columnModel)

Desktop/engine/enginerepresentation.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ void EngineRepresentation::processFilterReply(Json::Value & json)
342342
{
343343
checkIfExpectedReplyType(engineState::filter);
344344

345+
345346
setState(engineState::idle);
346347

347348
#ifdef PRINT_ENGINE_MESSAGES
@@ -350,10 +351,15 @@ void EngineRepresentation::processFilterReply(Json::Value & json)
350351

351352
int requestId = json.get("requestId", -1).asInt();
352353

353-
emit filterDone(requestId);
354-
355354
if(requestId == _lastRequestId)
356-
emit processNewFilterResult(requestId);
355+
{
356+
emit filterDone(requestId);
357+
358+
if(json.isMember("error"))
359+
emit processFilterErrorMsg(tq(json["error"].asString()), requestId);
360+
else
361+
emit processNewFilterResult(requestId);
362+
}
357363
}
358364

359365
void EngineRepresentation::runScriptOnProcess(const QString & rCmdCode)

Engine/engine.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ void Engine::runFilter(const std::string & filter, const std::string & generated
300300
std::vector<bool> filterResult = rbridge_applyFilter(strippedFilter, generatedFilter);
301301
std::string RPossibleWarning = jaspRCPP_getLastErrorMsg();
302302

303+
Log::log() << "Engine::runFilter ran:\n\t" << strippedFilter << "\n\tRPossibleWarning='" << RPossibleWarning << "'\n\t\tfor revision " << _dataSet->filter()->revision() << std::endl;
304+
303305
_dataSet->db().transactionWriteBegin();
304306
_dataSet->filter()->setRFilter(filter);
305307
_dataSet->filter()->setFilterVector(filterResult);
@@ -313,7 +315,14 @@ void Engine::runFilter(const std::string & filter, const std::string & generated
313315
}
314316
catch(filterException & e)
315317
{
316-
sendFilterError(filterRequestId, std::string(e.what()).length() > 0 ? e.what() : "Something went wrong with the filter but it is unclear what.");
318+
std::string error = std::string(e.what()).length() > 0 ? e.what() : "Something went wrong with the filter but it is unclear what.";
319+
320+
_dataSet->db().transactionWriteBegin();
321+
_dataSet->filter()->setErrorMsg(error);
322+
_dataSet->filter()->incRevision();
323+
_dataSet->db().transactionWriteEnd();
324+
325+
sendFilterError(filterRequestId, error);
317326
}
318327

319328
_engineState = engineState::idle;
@@ -336,10 +345,11 @@ void Engine::sendFilterError(int filterRequestId, const std::string & errorMessa
336345
{
337346
Json::Value filterResponse = Json::Value(Json::objectValue);
338347

339-
provideAndUpdateDataSet()->filter()->setErrorMsg(errorMessage);
348+
Log::log() << "Engine::sendFilterError(filterRequestId=" << filterRequestId << ", errorMsg='" << errorMessage << "')" << std::endl;
340349

341350
filterResponse["typeRequest"] = engineStateToString(engineState::filter);
342351
filterResponse["requestId"] = filterRequestId;
352+
filterResponse["error"] = errorMessage;
343353

344354
sendString(filterResponse.toStyledString());
345355
}
@@ -862,11 +872,11 @@ void Engine::removeNonKeepFiles(const Json::Value & filesToKeepValue)
862872

863873
DataSet * Engine::provideAndUpdateDataSet()
864874
{
865-
JASPTIMER_RESUME(Engine::provideDataSet());
875+
JASPTIMER_RESUME(Engine::provideAndUpdateDataSet());
866876

867877
if(_dataSet)
868878
{
869-
Log::log() << "There is a dataset, ";
879+
Log::log() << "Engine::provideAndUpdateDataSet(): There is a dataset, ";
870880
if(_dataSet->checkForUpdates())
871881
{
872882
Log::log(false) << "updates found, loading them.";

R-Interface/jasprcpp.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ int STDCALL jaspRCPP_runFilter(const char * filterCode, bool ** arrayPointer)
345345
{
346346
jaspRCPP_logString("jaspRCPP_runFilter runs: \n\"" + std::string(filterCode) + "\"\n" );
347347

348-
lastErrorMessage = "";
348+
jaspRCPP_resetErrorMsg();
349349
rinside->instance()[".filterCode"] = filterCode;
350350

351351
const std::string filterTryCatch(

0 commit comments

Comments
 (0)