Skip to content

Commit

Permalink
move more stuff from FilterModel to FilterQ
Browse files Browse the repository at this point in the history
  • Loading branch information
JorisGoosen committed Jan 21, 2025
1 parent b19360f commit 8e73a38
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 251 deletions.
22 changes: 18 additions & 4 deletions CommonData/filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ void Filter::dbLoad()
db().filterLoad(_id, _rFilter, _generatedFilter, _constructorJson, _constructorR, _revision, nameInDB, _invalidated);
assert(nameInDB == _name);

rescanForColumns();

if(oldRFilter != _rFilter) _rFilterChanged();
if(oldGeneratedFilter != _generatedFilter) _generatedFilterChanged();
if(oldConstructorJson != _constructorJson) _constructorJsonChanged();
if(oldConstructorR != _constructorR) _constructorRChanged();

_columnsInConstructorJson = JsonUtilities::convertDragNDropFilterJSONToSet(_constructorJson);

db().filterSelect(_id, _filtered);
calculateFilteredRowCount();

Expand Down Expand Up @@ -190,6 +190,9 @@ void Filter::setRFilter(const std::string &rFilter)
{
bool wasChange =_rFilter != rFilter;
_rFilter = rFilter;

rescanForColumns();

dbUpdate();

if(wasChange)
Expand Down Expand Up @@ -226,8 +229,9 @@ void Filter::setConstructorJson(const std::string &constructorJson)
{
bool wasChange =_constructorJson != constructorJson;
_constructorJson = constructorJson;
_columnsInConstructorJson = JsonUtilities::convertDragNDropFilterJSONToSet(_constructorJson);


rescanForColumns();

dbUpdate();

if(wasChange)
Expand Down Expand Up @@ -273,6 +277,11 @@ stringset Filter::columnsUsedInConstructor() const
return _columnsInConstructorJson;
}

stringset Filter::columnsUsedInRFilter() const
{
return _columnsUsedInRFilter;
}

bool Filter::filterNameIsFree(const std::string &filterName)
{
return -1 == DatabaseInterface::singleton()->filterGetId(filterName);
Expand All @@ -290,3 +299,8 @@ void Filter::reset()
DatabaseInterface & Filter::db() { return *DatabaseInterface::singleton(); }
const DatabaseInterface & Filter::db() const { return *DatabaseInterface::singleton(); }

void Filter::rescanForColumns()
{
_columnsUsedInRFilter = data()->findUsedColumnNames(_rFilter);
_columnsInConstructorJson = JsonUtilities::convertDragNDropFilterJSONToSet(_constructorJson);
}
9 changes: 7 additions & 2 deletions CommonData/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ class Filter : public DataSetBaseNode
void incRevision() override;
bool checkForUpdates();

stringset columnsUsedInConstructor() const;

stringset columnsUsedInConstructor() const;
stringset columnsUsedInRFilter() const;

static bool filterNameIsFree(const std::string & filterName);

Expand All @@ -77,6 +79,8 @@ class Filter : public DataSetBaseNode

protected:
void calculateFilteredRowCount();
void rescanForColumns();

std::function<void()> _nameChanged;
std::function<void()> _rFilterChanged;
std::function<void()> _generatedFilterChanged;
Expand All @@ -99,7 +103,8 @@ class Filter : public DataSetBaseNode
_name = "";
bool _invalidated = false;
boolvec _filtered;
stringset _columnsInConstructorJson;
stringset _columnsInConstructorJson,
_columnsUsedInRFilter;
};

#endif // FILTER_H
188 changes: 24 additions & 164 deletions Desktop/data/filtermodel.cpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
#include "timers.h"
#include "filtermodel.h"
#include "jsonutilities.h"
#include "columnencoder.h"
#include "timers.h"

Al deze dingen zullen bijna wel naar Filter(Q) toe moeten..
#include "datasetpackage.h"
#include "models/filterq.h"


FilterModel::FilterModel(labelFilterGenerator * labelFilterGenerator)
: QObject(DataSetPackage::pkg()), _labelFilterGenerator(labelFilterGenerator)
FilterModel::FilterModel(QObject * parent)
: QObject(parent)
{
_undoStack = DataSetPackage::pkg()->undoStack();

reset();
connect(this, &FilterModel::rFilterChanged, this, &FilterModel::rescanRFilterForColumns );
connect(DataSetPackage::pkg(), &DataSetPackage::modelReset, this, &FilterModel::dataSetPackageResetDone );
connect(DataSetPackage::pkg(), &DataSetPackage::modelInit, this, &FilterModel::modelInit );
}

QString FilterModel::rFilter() const { return !DataSetPackage::filter() ? defaultRFilter() : tq(DataSetPackage::filter()->rFilter()); }
QString FilterModel::constructorR() const { return !DataSetPackage::filter() ? "" : tq(DataSetPackage::filter()->constructorR()); }
QString FilterModel::filterErrorMsg() const { return !DataSetPackage::filter() ? "" : tq(DataSetPackage::filter()->errorMsg()); }
QString FilterModel::generatedFilter() const { return !DataSetPackage::filter() ? DEFAULT_FILTER_GEN : tq(DataSetPackage::filter()->generatedFilter()); }
QString FilterModel::constructorJson() const { return !DataSetPackage::filter() ? DEFAULT_FILTER_JSON : tq(DataSetPackage::filter()->constructorJson()); }
QString FilterModel::rFilter() const { return !filter() ? defaultRFilter() : tq(filter()->rFilter()); }
QString FilterModel::constructorR() const { return !filter() ? "" : tq(filter()->constructorR()); }
QString FilterModel::filterErrorMsg() const { return !filter() ? "" : tq(filter()->errorMsg()); }
QString FilterModel::generatedFilter() const { return !filter() ? DEFAULT_FILTER_GEN : tq(filter()->generatedFilter()); }
QString FilterModel::constructorJson() const { return !filter() ? DEFAULT_FILTER_JSON : tq(filter()->constructorJson()); }

const char * FilterModel::defaultRFilter()
{
Expand All @@ -41,12 +39,7 @@ const char * FilterModel::defaultRFilter()

void FilterModel::reset()
{
_setGeneratedFilter(DEFAULT_FILTER_GEN );
setConstructorJson( DEFAULT_FILTER_JSON );
_setRFilter( defaultRFilter() );

if(DataSetPackage::pkg()->dataRowCount() > 0)
sendGeneratedAndRFilter();
implement me
}

void FilterModel::dataSetPackageResetDone()
Expand All @@ -59,35 +52,14 @@ void FilterModel::dataSetPackageResetDone()
void FilterModel::modelInit()
{
if(!DataSetPackage::pkg()->isJaspFile() || DataSetPackage::pkg()->filterShouldRunInit()) //Either this wasn't a JASP file (archive) and we need to run the filter after loading, or it *is* a JASP file but it is old (<0.11) and doesn't have filterVector stored in it yet.
sendGeneratedAndRFilter();
runFilter()();

DataSetPackage::pkg()->setFilterShouldRunInit(true); //Make sure next time we come here (because of computed columns or something) we do actually run the filter
}

void FilterModel::setRFilter(QString newRFilter)
{
if (_setRFilter(newRFilter))
sendGeneratedAndRFilter();
}

bool FilterModel::_setRFilter(const QString& newRFilter)
{
if(newRFilter != rFilter())
{
bool oldHasFilter = hasFilter();

if(DataSetPackage::filter())
DataSetPackage::filter()->setRFilter(fq(newRFilter));

if(oldHasFilter != hasFilter())
emit hasFilterChanged();

emit rFilterChanged();

return true;
}

return false;
filter()->setRFilter
}

void FilterModel::setFilterErrorMsg( QString newFilterErrorMsg)
Expand All @@ -104,13 +76,13 @@ void FilterModel::setFilterErrorMsg( QString newFilterErrorMsg)
void FilterModel::applyConstructorJson(QString newConstructorJson)
{
if (newConstructorJson != constructorJson())
_undoStack->pushCommand(new SetJsonFilterCommand(DataSetPackage::pkg(), this, newConstructorJson));
_undoStack->pushCommand(new SetJsonFilterCommand(filter(), newConstructorJson));
}

void FilterModel::applyRFilter(QString newRFilter)
{
if (newRFilter != rFilter())
_undoStack->pushCommand(new SetRFilterCommand(DataSetPackage::pkg(), this, newRFilter));
_undoStack->pushCommand(new SetRFilterCommand(filter(), newRFilter));
}

void FilterModel::setConstructorJson(QString newconstructorJson)
Expand Down Expand Up @@ -151,40 +123,17 @@ void FilterModel::setGeneratedFilter(QString newGeneratedFilter)
{
JASPTIMER_SCOPE(FilterModel::setGeneratedFilter);

_setGeneratedFilter(newGeneratedFilter);
// After this commit https://github.com/jasp-stats/jasp-desktop/commit/65f007cba2ff8986fc3ad86ac4b1a00fa706769b the filter was not executed.
// If a model reset is called just before, this will set the generatedFilter to the right value, and _setGeneratedFilter will returns false
// But the engine did not compute yet the filter. So send the filter to the engine always.
sendGeneratedAndRFilter();
runFilter();
}

bool FilterModel::_setGeneratedFilter(const QString& newGeneratedFilter)
{
JASPTIMER_SCOPE(FilterModel::_setGeneratedFilter);

if (newGeneratedFilter != generatedFilter())
{
if(DataSetPackage::filter())
DataSetPackage::filter()->setGeneratedFilter(fq(newGeneratedFilter));

emit generatedFilterChanged(); //does nothing?
return true;
}

return false;
}


void FilterModel::processFilterResult(int requestId)
void FilterModel::processFilterResult()
{
if((requestId < _lastSentRequestId))
return;

if(!(DataSetPackage::pkg()->dataSet() || DataSetPackage::pkg()->dataSet()->shownFilter()))
if(filter())
return;

//Load new filter values from database
if(DataSetPackage::pkg()->dataSet()->shownFilter()->dbLoadResultAndError())
if(filter()->dbLoadResultAndError())
{
emit filterErrorMsgChanged();
emit refreshAllAnalyses();
Expand All @@ -193,104 +142,15 @@ void FilterModel::processFilterResult(int requestId)
}
}

void FilterModel::processFilterErrorMsg(QString filterErrorMsg, int requestId)
{
if(requestId == _lastSentRequestId || requestId == -1)
setFilterErrorMsg(filterErrorMsg);
}

void FilterModel::sendGeneratedAndRFilter()
{
JASPTIMER_SCOPE(FilterModel::sendGeneratedAndRFilter);

setFilterErrorMsg("");
_lastSentRequestId = emit sendFilter(generatedFilter(), rFilter());
}

void FilterModel::updateStatusBar()
{
if(!DataSetPackage::pkg()->hasDataSet())
{
setStatusBarText(tr("No data loaded!"));
return;
}

int TotalCount = DataSetPackage::pkg()->dataRowCount(),
TotalThroughFilter = DataSetPackage::pkg()->filteredRowCount();
int PercentageThrough = (int)round(100.0 * ((double)TotalThroughFilter) / ((double)TotalCount));
bool Approximate = PercentageThrough != TotalThroughFilter;

setStatusBarText(tr("Data has %1 rows, %2 (%3%4%) passed through filter").arg(TotalCount).arg(TotalThroughFilter).arg(Approximate ? "~" : "").arg(PercentageThrough));
}

void FilterModel::rescanRFilterForColumns()
void FilterModel::runFilter()
{
_columnsUsedInRFilter = DataSetPackage::pkg() && DataSetPackage::pkg()->dataSet() ? DataSetPackage::pkg()->dataSet()->findUsedColumnNames(fq(rFilter())) : stringset();
filter()->setInvalidated(true);
Also run it somehow!
}

void FilterModel::computeColumnSucceeded(QString columnName, QString, bool dataChanged)
{
if(dataChanged && (_columnsUsedInConstructedFilter.count(columnName.toStdString()) > 0 || _columnsUsedInRFilter.count(columnName.toStdString()) > 0))
sendGeneratedAndRFilter();
if(dataChanged && filter()->columnUsed(columnName))
runFilter();
}

void FilterModel::datasetChanged( QStringList changedColumns,
QStringList missingColumns,
QMap<QString, QString> changeNameColumns,
bool rowCountChanged,
bool /*hasNewColumns*/)
{
bool invalidateMe = rowCountChanged;

if(!invalidateMe)
for(const QString & changed : changedColumns)
if(_columnsUsedInRFilter.count(fq(changed)) > 0 || _columnsUsedInConstructedFilter.count(fq(changed)) > 0)
{
invalidateMe = true;
break;
}

auto iUseOneOfTheseColumns = [&](std::vector<std::string> cols) -> bool
{
for(const std::string & col : cols)
if(_columnsUsedInRFilter.count(col) > 0 || _columnsUsedInConstructedFilter.count(col) > 0)
return true;

return false;
};

if(iUseOneOfTheseColumns(fq(changeNameColumns.keys())))
{
std::map<std::string, std::string> stdChangeNameCols(fq(changeNameColumns));

invalidateMe = true;

setRFilter( tq(ColumnEncoder::replaceColumnNamesInRScript(fq(rFilter()), stdChangeNameCols)));
setConstructorJson( tq(JsonUtilities::replaceColumnNamesInDragNDropFilterJSONStr(fq(constructorJson()), stdChangeNameCols)));
}

auto missingStd = fq(missingColumns);
if(iUseOneOfTheseColumns(missingStd))
{
setRFilter(tq(ColumnEncoder::removeColumnNamesFromRScript(fq(rFilter()), missingStd)));

setConstructorJson( tq(JsonUtilities::removeColumnsFromDragNDropFilterJSONStr( fq(constructorJson()), missingStd)));

invalidateMe = false; //Actually, if stuff is removed from the filter it won't work will it now?

//Just reset the filter result to everything true while the user gets the change to fix their now broken filter
if(DataSetPackage::filter())
DataSetPackage::filter()->reset();

emit refreshAllAnalyses();
emit filterUpdated();
updateStatusBar();

//The following errormsg is overwritten immediately but that is because constructorJson changed triggers qml which triggers (some vents later) a send event. So yeah...
//Ill leave it here though because it would be nice to show this friendlier msg then "null not found"
setFilterErrorMsg("Some columns were removed from the data and your filter(s)!");
}

if(invalidateMe)
sendGeneratedAndRFilter();
}
Loading

0 comments on commit 8e73a38

Please sign in to comment.