From 8e73a38a9da7a1e15b56a1b6233c1727032a7b07 Mon Sep 17 00:00:00 2001 From: Joris Goosen Date: Tue, 21 Jan 2025 18:51:41 +0100 Subject: [PATCH] move more stuff from FilterModel to FilterQ --- CommonData/filter.cpp | 22 ++- CommonData/filter.h | 9 +- Desktop/data/filtermodel.cpp | 188 +++---------------- Desktop/data/filtermodel.h | 50 ++--- Desktop/data/models/datasetq.cpp | 12 ++ Desktop/data/models/datasetq.h | 9 +- Desktop/data/models/filterq.cpp | 94 +++++++++- Desktop/data/models/filterq.h | 10 +- Desktop/data/models/labelfiltergenerator.cpp | 8 +- Desktop/data/models/labelfiltergenerator.h | 2 +- Desktop/data/undostack.cpp | 41 ++-- Desktop/data/undostack.h | 14 +- Desktop/mainwindow.cpp | 5 +- Desktop/mainwindow.h | 2 - 14 files changed, 215 insertions(+), 251 deletions(-) diff --git a/CommonData/filter.cpp b/CommonData/filter.cpp index 69bb02f02a..507c6465d8 100644 --- a/CommonData/filter.cpp +++ b/CommonData/filter.cpp @@ -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(); @@ -190,6 +190,9 @@ void Filter::setRFilter(const std::string &rFilter) { bool wasChange =_rFilter != rFilter; _rFilter = rFilter; + + rescanForColumns(); + dbUpdate(); if(wasChange) @@ -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) @@ -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); @@ -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); +} diff --git a/CommonData/filter.h b/CommonData/filter.h index 279313c467..705e32a91a 100644 --- a/CommonData/filter.h +++ b/CommonData/filter.h @@ -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); @@ -77,6 +79,8 @@ class Filter : public DataSetBaseNode protected: void calculateFilteredRowCount(); + void rescanForColumns(); + std::function _nameChanged; std::function _rFilterChanged; std::function _generatedFilterChanged; @@ -99,7 +103,8 @@ class Filter : public DataSetBaseNode _name = ""; bool _invalidated = false; boolvec _filtered; - stringset _columnsInConstructorJson; + stringset _columnsInConstructorJson, + _columnsUsedInRFilter; }; #endif // FILTER_H diff --git a/Desktop/data/filtermodel.cpp b/Desktop/data/filtermodel.cpp index 49cdf86d88..9e997b830d 100644 --- a/Desktop/data/filtermodel.cpp +++ b/Desktop/data/filtermodel.cpp @@ -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() { @@ -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() @@ -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) @@ -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) @@ -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(); @@ -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 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 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 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(); -} diff --git a/Desktop/data/filtermodel.h b/Desktop/data/filtermodel.h index bbe916150c..13c7b346b9 100644 --- a/Desktop/data/filtermodel.h +++ b/Desktop/data/filtermodel.h @@ -3,47 +3,39 @@ #include #include "utilities/qutils.h" -#include "labelfiltergenerator.h" + +class FilterQ; +class UndoStack; /// -/// Backend for the filter gui +/// Passthrough for the filter gui class FilterModel : public QObject { Q_OBJECT public: - explicit FilterModel(labelFilterGenerator * labelfilterGenerator); + explicit FilterModel(QObject * parent = nullptr); + FilterQ * filter() const; void init(); QString rFilter() const; QString constructorR() const; - QString statusBarText() const { return _statusBarText; } + QString statusBarText() const; QString filterErrorMsg() const; QString generatedFilter() const; QString constructorJson() const; static const char * defaultRFilter(); + bool hasFilter() const; - bool hasFilter() const { return rFilter() != defaultRFilter() || constructorJson() != DEFAULT_FILTER_JSON; } - - - Q_INVOKABLE void resetRFilter() { applyRFilter(defaultRFilter()); } - void sendGeneratedAndRFilter(); + void runFilter(); void updateStatusBar(); void reset(); void modelInit(); public slots: - GENERIC_SET_FUNCTION(StatusBarText, _statusBarText, statusBarTextChanged, QString) - - void setRFilter( QString newRFilter); - void setConstructorR( QString newConstructorR); - void setGeneratedFilter(QString newGeneratedFilter); - void setConstructorJson(QString newconstructorJson); - void setFilterErrorMsg( QString newFilterErrorMsg); - void applyConstructorJson( QString constructorJson); void applyRFilter( QString rFilter); @@ -54,11 +46,6 @@ public slots: void computeColumnSucceeded(QString columnName, QString warning, bool dataChanged); void dataSetPackageResetDone(); - void datasetChanged( QStringList changedColumns, - QStringList missingColumns, - QMap changeNameColumns, - bool rowCountChanged, - bool hasNewColumns); signals: void rFilterChanged(); @@ -70,27 +57,12 @@ public slots: void constructorJsonChanged(); void updateColumnsUsedInConstructedFilter(std::set columnNames); - + void resetRFilter(); void refreshAllAnalyses(); void filterUpdated(); - - int sendFilter(QString generatedFilter, QString rFilter); - - void defaultRFilterChanged(); //Will never be called - -private: - bool _setGeneratedFilter(const QString& newGeneratedFilter); - bool _setRFilter(const QString& newRFilter); + int sendFilter(QString generatedFilter, QString rFilter); private: - labelFilterGenerator * _labelFilterGenerator = nullptr; - QString _statusBarText = ""; - - std::set _columnsUsedInConstructedFilter, - _columnsUsedInRFilter; - - int _lastSentRequestId = 0; - UndoStack* _undoStack = nullptr; }; diff --git a/Desktop/data/models/datasetq.cpp b/Desktop/data/models/datasetq.cpp index 9ec253e2dd..7a41c46cc5 100644 --- a/Desktop/data/models/datasetq.cpp +++ b/Desktop/data/models/datasetq.cpp @@ -17,6 +17,8 @@ DataSetQ::DataSetQ(int index) _databaseJsonChanged = [this](){ emit databaseJsonChanged(); }; _dataSynchChanged = [this](){ emit dataFileSynchChanged(); }; _dataTimestampChanged = [this](){ emit dataTimestampChanged(); }; + + connect(this, &DataSetQ::datasetChanged, this, &DataSetQ::handleDataSetChanged); } DataSetQ::~DataSetQ() @@ -480,6 +482,16 @@ void DataSetQ::handleColumnTypeChanged(ColumnQ *column) emit columnTypeChanged(tq(column->name())); } +void DataSetQ::handleDataSetChanged(QStringList changedColumns, + QStringList missingColumns, + QMap changeNameColumns, + bool rowCountChanged, + bool hasNewColumns) +{ + if(rowCountChanged) + DataSetQ::rowCountChanged(); +} + bool DataSetQ::getRowFilter(int row) const { return bool(shownFilter()->filtered().at(row)); diff --git a/Desktop/data/models/datasetq.h b/Desktop/data/models/datasetq.h index 485bd5205a..dcf8cd244f 100644 --- a/Desktop/data/models/datasetq.h +++ b/Desktop/data/models/datasetq.h @@ -84,14 +84,21 @@ friend ColumnQ; void dataFileSynchChanged(); void dataTimestampChanged(); void columnsFilteredCountChanged(); + void rowCountChanged(); - public slots: void refresh() { beginResetModel(); endResetModel(); } void handleColumnChanged( ColumnQ * column); void handleLabelsReordered( ColumnQ * column); void handleColumnTypeChanged( ColumnQ * column); void handleColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last) { emit columnsBeingRemoved(first, (last-first)+1); } + + private slots: + void handleDataSetChanged( QStringList changedColumns, + QStringList missingColumns, + QMap changeNameColumns, + bool rowCountChanged, + bool hasNewColumns); protected: QList getColumnValuesAsDoubleList(int columnIndex) const; diff --git a/Desktop/data/models/filterq.cpp b/Desktop/data/models/filterq.cpp index ce039070c2..95eea857ce 100644 --- a/Desktop/data/models/filterq.cpp +++ b/Desktop/data/models/filterq.cpp @@ -7,13 +7,16 @@ FilterQ::FilterQ(DataSetQ * data) : Filter(data), _labelGen(new LabelFilterGenerator(this)) { - connect(data, &DataSetQ::labelFilterChanged, _labelGen, &LabelFilterGenerator::labelFilterChanged); + connect(data, &DataSetQ::labelFilterChanged, _labelGen, &LabelFilterGenerator::regenerateGeneratedFilter); + connect(this, &FilterQ::constructorRChanged, _labelGen, &LabelFilterGenerator::regenerateGeneratedFilter); + connect(this, &FilterQ::filteredRowCountChanged, this, &FilterQ::updateStatusBar ); + connect(data, &DataSetQ::datasetChanged, this, &FilterQ::datasetChanged ); } FilterQ::FilterQ(DataSetQ * data, const std::string & name, bool createIfMissing) : Filter(data, name, createIfMissing) { - + updateStatusBar(); } DataSetQ * FilterQ::dataQ() const @@ -28,6 +31,11 @@ QString FilterQ::filterErrorMsgQ() const { return tq(Filter::errorMsg()); } QString FilterQ::generatedFilterQ() const { return tq(Filter::generatedFilter()); } QString FilterQ::constructorJsonQ() const { return tq(Filter::constructorJson()); } +bool FilterQ::columnUsed(const QString &name) const +{ + return columnsUsedInConstructor().count(fq(name)) > 0 || columnsUsedInRFilter().count(fq(name)) > 0; +} + bool FilterQ::hasFilter() const { return rFilter() != defaultRFilter() || constructorJson() != DEFAULT_FILTER_JSON; @@ -39,6 +47,26 @@ void FilterQ::setGeneratedFilter( const QString &newGeneratedFilter ) { Filter:: void FilterQ::setConstructorJson( const QString &newconstructorJson ) { Filter::setConstructorJson( fq(newconstructorJson)); } void FilterQ::setFilterErrorMsg( const QString &newFilterErrorMsg ) { Filter::setErrorMsg( fq(newFilterErrorMsg)); } +void FilterQ::setStatusBarText(const QString &newStatusBarText) +{ + if(newStatusBarText != _statusBarText) + { + _statusBarText = newStatusBarText; + emit statusBarTextChanged(); + } +} + +void FilterQ::updateStatusBar() +{ + int TotalCount = data()->rowCount(), + TotalThroughFilter = filteredRowCount(); + double dblPercent = 100.0 * ((double)TotalThroughFilter) / ((double)TotalCount); + int PercentageThrough = (int)round(dblPercent); + bool Approximate = std::abs(dblPercent - double(PercentageThrough)) > 0.000001; + + setStatusBarText(tr("Data has %1 rows, %2 (%3%4%) passed through filter").arg(TotalCount).arg(TotalThroughFilter).arg(Approximate ? "~" : "").arg(PercentageThrough)); +} + void FilterQ::bindStdFunctionsToSignals() { _nameChanged = [this](){ emit nameChanged(); }; @@ -51,3 +79,65 @@ void FilterQ::bindStdFunctionsToSignals() _errorMsgChanged = [this](){ emit filterErrorMsgChanged(); }; } + +void FilterQ::datasetChanged( QStringList changedColumns, + QStringList missingColumns, + QMap changeNameColumns, + bool rowCountChanged, + bool /*hasNewColumns*/) +{ + bool invalidateMe = rowCountChanged; + + + if(!invalidateMe) + for(const QString & changed : changedColumns) + if(columnUsed(changed)) + { + invalidateMe = true; + break; + } + + auto iUseOneOfTheseColumns = [&](std::vector cols) -> bool + { + for(const std::string & col : cols) + if(columnUsed(tq(col))) + return true; + return false; + }; + + if(iUseOneOfTheseColumns(fq(changeNameColumns.keys()))) + { + strstrmap 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) + runFilter(); +} + diff --git a/Desktop/data/models/filterq.h b/Desktop/data/models/filterq.h index 5a235490fb..4a4104bc0f 100644 --- a/Desktop/data/models/filterq.h +++ b/Desktop/data/models/filterq.h @@ -1,7 +1,7 @@ #ifndef FILTERQ_H #define FILTERQ_H -#include +#include "filter.h" #include class DataSetQ; @@ -39,6 +39,8 @@ class FilterQ : public Filter, public QObject QString generatedFilterQ() const; QString constructorJsonQ() const; + bool columnUsed(const QString & name) const; + static const char * defaultRFilter(); bool hasFilter() const; @@ -48,10 +50,13 @@ class FilterQ : public Filter, public QObject void setGeneratedFilter( const QString & newGeneratedFilter ); void setConstructorJson( const QString & newconstructorJson ); void setFilterErrorMsg( const QString & newFilterErrorMsg ); + void setStatusBarText( const QString & newStatusBarText ); + signals: void nameChanged(); void rFilterChanged(); + void updateStatusBar(); void hasFilterChanged(); void invalidatedChanged(); void dataSetShouldRefresh(); @@ -62,6 +67,9 @@ class FilterQ : public Filter, public QObject void constructorJsonChanged(); void filteredRowCountChanged(); +protected slots: + void datasetChanged(QStringList changedColumns, QStringList missingColumns, QMap changeNameColumns, bool rowCountChanged, bool); + private: void bindStdFunctionsToSignals(); QString _statusBarText; diff --git a/Desktop/data/models/labelfiltergenerator.cpp b/Desktop/data/models/labelfiltergenerator.cpp index efd6bcf15d..3deff48e39 100644 --- a/Desktop/data/models/labelfiltergenerator.cpp +++ b/Desktop/data/models/labelfiltergenerator.cpp @@ -8,8 +8,8 @@ LabelFilterGenerator::LabelFilterGenerator(FilterQ * filter) : QObject(filter), _filter(filter) { - connect(_filter->dataQ(), &DataSetQ::labelFilterChanged, this, &LabelFilterGenerator::labelFilterChanged ); - connect(_filter->dataQ(), &DataSetQ::allFiltersReset, this, &LabelFilterGenerator::labelFilterChanged ); + connect(_filter->dataQ(), &DataSetQ::labelFilterChanged, this, &LabelFilterGenerator::regenerateGeneratedFilter ); + connect(_filter->dataQ(), &DataSetQ::allFiltersReset, this, &LabelFilterGenerator::regenerateGeneratedFilter ); } std::string LabelFilterGenerator::generateFilter() @@ -58,9 +58,9 @@ std::string LabelFilterGenerator::generateFilter() return newGeneratedFilter.str(); } -void LabelFilterGenerator::labelFilterChanged() +void LabelFilterGenerator::regenerateGeneratedFilter() { - JASPTIMER_SCOPE(LabelFilterGenerator::labelFilterChanged); + JASPTIMER_SCOPE(LabelFilterGenerator::regenerateGeneratedFilter); _filter->setGeneratedFilter(tq(generateFilter())); } diff --git a/Desktop/data/models/labelfiltergenerator.h b/Desktop/data/models/labelfiltergenerator.h index 1c58001c30..f052bcdaad 100644 --- a/Desktop/data/models/labelfiltergenerator.h +++ b/Desktop/data/models/labelfiltergenerator.h @@ -16,7 +16,7 @@ class LabelFilterGenerator : public QObject std::string generateFilter(); public slots: - void labelFilterChanged(); + void regenerateGeneratedFilter(); private: FilterQ * _filter = nullptr; diff --git a/Desktop/data/undostack.cpp b/Desktop/data/undostack.cpp index 2e3ee71392..7d77cad092 100644 --- a/Desktop/data/undostack.cpp +++ b/Desktop/data/undostack.cpp @@ -1,10 +1,11 @@ -#include "undostack.h" #include "log.h" -#include "datasettablemodel.h" +#include "undostack.h" #include "columnmodel.h" -#include "filtermodel.h" -#include "computedcolumnmodel.h" +#include "models/filterq.h" #include "utilities/qutils.h" +#include "datasettablemodel.h" +#include "datasetpackageenums.h" +#include "computedcolumnmodel.h" UndoStack* UndoStack::_undoStack = nullptr; @@ -224,8 +225,8 @@ PasteSpreadsheetCommand::PasteSpreadsheetCommand(QAbstractItemModel *model, int _oldColNames.push_back(_model->headerData(_col + c, Qt::Horizontal).toString()); for (int r = 0; r < _newValues[c].size(); r++) { - _oldValues[c].push_back(!isSelected(r,c) ? "" : _model->data(_model->index(_row + r, _col + c), int(DataSetPackage::specialRoles::value)).toString()); - _oldLabels[c].push_back(!isSelected(r,c) ? "" : _model->data(_model->index(_row + r, _col + c), int(DataSetPackage::specialRoles::label)).toString()); + _oldValues[c].push_back(!isSelected(r,c) ? "" : _model->data(_model->index(_row + r, _col + c), int(dataPkgRoles::value)).toString()); + _oldLabels[c].push_back(!isSelected(r,c) ? "" : _model->data(_model->index(_row + r, _col + c), int(dataPkgRoles::label)).toString()); } } } @@ -470,7 +471,7 @@ SetLabelCommand::SetLabelCommand(QAbstractItemModel *model, int labelIndex, QStr if (_columnModel) { _oldLabel = _model->data(_model->index(_labelIndex, 0)).toString(); - QString value = _model->data(_model->index(_labelIndex, 0), int(DataSetPackage::specialRoles::label)).toString(); + QString value = _model->data(_model->index(_labelIndex, 0), int(dataPkgRoles::label)).toString(); setText(QObject::tr("Set label for value '%1' of column '%2' from '%3' to '%4'").arg(value).arg(columnName()).arg(_oldLabel).arg(_newLabel)); } else @@ -483,7 +484,7 @@ SetLabelCommand::SetLabelCommand(QAbstractItemModel *model, int labelIndex, QStr void SetLabelCommand::redo() { UndoModelCommandLabelChange::redo(); - _model->setData(_model->index(_labelIndex, 0), _newLabel, int(DataSetPackage::specialRoles::label)); + _model->setData(_model->index(_labelIndex, 0), _newLabel, int(dataPkgRoles::label)); _columnModel->setLabelMaxWidth(); } @@ -492,8 +493,8 @@ SetLabelOriginalValueCommand::SetLabelOriginalValueCommand(QAbstractItemModel *m { if (_columnModel) { - _oldOriginalValue = _model->data(_model->index(_labelIndex, 0), int(DataSetPackage::specialRoles::value)).toString(); - _oldLabel = _model->data(_model->index(_labelIndex, 0), int(DataSetPackage::specialRoles::label)).toString(); + _oldOriginalValue = _model->data(_model->index(_labelIndex, 0), int(dataPkgRoles::value)).toString(); + _oldLabel = _model->data(_model->index(_labelIndex, 0), int(dataPkgRoles::label)).toString(); setText(QObject::tr("Set original value from '%3' to '%4' for label '%1' of column '%2'").arg(_oldLabel).arg(columnName()).arg(_oldOriginalValue).arg(_newOriginalValue)); } else @@ -506,7 +507,7 @@ SetLabelOriginalValueCommand::SetLabelOriginalValueCommand(QAbstractItemModel *m void SetLabelOriginalValueCommand::redo() { UndoModelCommandLabelChange::redo(); - _model->setData(_model->index(_labelIndex, 0), _newOriginalValue, int(DataSetPackage::specialRoles::value)); + _model->setData(_model->index(_labelIndex, 0), _newOriginalValue, int(dataPkgRoles::value)); _columnModel->setLabelMaxWidth(); } @@ -536,13 +537,13 @@ FilterLabelCommand::FilterLabelCommand(QAbstractItemModel *model, int labelIndex void FilterLabelCommand::undo() { _columnModel->setChosenColumn(_colId); - _model->setData(_model->index(_labelIndex, 0), !_checked, int(DataSetPackage::specialRoles::filter)); + _model->setData(_model->index(_labelIndex, 0), !_checked, int(dataPkgRoles::filter)); } void FilterLabelCommand::redo() { _columnModel->setChosenColumn(_colId); - _model->setData(_model->index(_labelIndex, 0), _checked, int(DataSetPackage::specialRoles::filter)); + _model->setData(_model->index(_labelIndex, 0), _checked, int(dataPkgRoles::filter)); } MoveLabelCommand::MoveLabelCommand(QAbstractItemModel *model, const std::vector &indexes, bool up) @@ -630,25 +631,25 @@ void ReverseLabelCommand::redo() DataSetPackage::pkg()->labelReverse(_colId); //through DataSetPackage to make sure signals get sent } -SetJsonFilterCommand::SetJsonFilterCommand(QAbstractItemModel *model, FilterModel* filterModel, const QString& newJsonValue) - : UndoModelCommand(model), _filterModel{filterModel}, _newJsonValue{newJsonValue} +SetJsonFilterCommand::SetJsonFilterCommand(FilterQ * filter, const QString& newJsonValue) + : UndoModelCommand(), _filter{filter}, _newJsonValue{newJsonValue} { setText(QObject::tr("Change drag and drop filter")); } void SetJsonFilterCommand::undo() { - _filterModel->setConstructorJson(_oldJsonValue); + _filter->setConstructorJson(_oldJsonValue); } void SetJsonFilterCommand::redo() { - _oldJsonValue = _filterModel->constructorJson(); - _filterModel->setConstructorJson(_newJsonValue); + _oldJsonValue = _filter->constructorJson(); + _filter->setConstructorJson(_newJsonValue); } -SetRFilterCommand::SetRFilterCommand(QAbstractItemModel *model, FilterModel* filterModel, const QString& newRFilter) - : UndoModelCommand(model), _filterModel{filterModel}, _newRFilter{newRFilter} +SetRFilterCommand::SetRFilterCommand(FilterQ * filter, const QString& newRFilter) + : UndoModelCommand(), _filter{filter}, _newRFilter{newRFilter} { setText(QObject::tr("Change R filter")); } diff --git a/Desktop/data/undostack.h b/Desktop/data/undostack.h index 6f36cce08a..3c9e26d474 100644 --- a/Desktop/data/undostack.h +++ b/Desktop/data/undostack.h @@ -1,13 +1,13 @@ #ifndef UNDOSTACK_H #define UNDOSTACK_H +#include "utils.h" #include -#include #include -#include "stringutils.h" +#include +class FilterQ; class ColumnModel; -class FilterModel; class ComputedColumnModel; class UndoModelCommand : public QUndoCommand @@ -147,13 +147,13 @@ class ReverseLabelCommand: public UndoModelCommand class SetJsonFilterCommand: public UndoModelCommand { public: - SetJsonFilterCommand(QAbstractItemModel *model, FilterModel* filterModel, const QString& newJsonValue); + SetJsonFilterCommand(FilterQ * filter, const QString& newJsonValue); void undo() override; void redo() override; private: - FilterModel* _filterModel = nullptr; + FilterQ * _filter; QString _oldJsonValue, _newJsonValue; }; @@ -161,13 +161,13 @@ class SetJsonFilterCommand: public UndoModelCommand class SetRFilterCommand: public UndoModelCommand { public: - SetRFilterCommand(QAbstractItemModel *model, FilterModel* filterModel, const QString& newRValue); + SetRFilterCommand(FilterQ* filter, const QString& newRValue); void undo() override; void redo() override; private: - FilterModel* _filterModel = nullptr; + FilterQ * _filter; QString _oldRFilter, _newRFilter; }; diff --git a/Desktop/mainwindow.cpp b/Desktop/mainwindow.cpp index e8d93971c6..a0f0f30401 100644 --- a/Desktop/mainwindow.cpp +++ b/Desktop/mainwindow.cpp @@ -136,11 +136,10 @@ MainWindow::MainWindow(QApplication * application) : QObject(application), _appl _resultsJsInterface = new ResultsJsInterface(); _odm = new OnlineDataManager(this); - _labelFilterGenerator = new labelFilterGenerator(_columnModel, this); _columnsModel = new ColumnsModel(_dataSetModelVarInfo); // We do not want filtered-out columns/levels to be selectable in other guis, see: https://github.com/jasp-stats/INTERNAL-jasp/issues/2322 _workspaceModel = new WorkspaceModel(this); _computedColumnsModel = new ComputedColumnModel(); - _filterModel = new FilterModel(_labelFilterGenerator); + _filterModel = new FilterModel(this); _ribbonModel = new RibbonModel(); _ribbonModelFiltered = new RibbonModelFiltered(this, _ribbonModel); _ribbonModelUncommon = new RibbonModelUncommon(this, _ribbonModel); @@ -548,8 +547,6 @@ void MainWindow::makeConnections() connect(_filterModel, &FilterModel::filterUpdated, [&]() { _package->resetFilterCounters(); emit _columnsModel->filterChanged(); } ); connect(_filterModel, &FilterModel::sendFilter, _engineSync, &EngineSync::sendFilter ); - connect(_labelFilterGenerator, &labelFilterGenerator::setGeneratedFilter, _filterModel, &FilterModel::setGeneratedFilter, Qt::QueuedConnection); - connect(_ribbonModel, &RibbonModel::analysisClickedSignal, _analyses, &Analyses::analysisClickedHandler ); connect(_ribbonModel, &RibbonModel::showRCommander, this, &MainWindow::showRCommander ); connect(_ribbonModel, &RibbonModel::dataModeChanged, _package, &DataSetPackage::dataModeChanged ); diff --git a/Desktop/mainwindow.h b/Desktop/mainwindow.h index 2512b4294c..12ca65289c 100644 --- a/Desktop/mainwindow.h +++ b/Desktop/mainwindow.h @@ -34,7 +34,6 @@ #include "data/fileevent.h" #include "data/filtermodel.h" #include "data/columnmodel.h" -#include "data/labelfiltergenerator.h" #include "engine/enginesync.h" #include "gui/aboutmodel.h" #include "models/columntypesmodel.h" @@ -300,7 +299,6 @@ private slots: DataSetPackage * _package = nullptr; DataSetTableModel * _datasetTableModel = nullptr, * _dataSetModelVarInfo = nullptr; - labelFilterGenerator * _labelFilterGenerator = nullptr; ColumnsModel * _columnsModel = nullptr; ComputedColumnModel * _computedColumnsModel = nullptr; FilterModel * _filterModel = nullptr;