From de4e6792c67992747d3deecd080ca95a7b15e81d Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Tue, 22 Jan 2019 09:32:39 +0100 Subject: [PATCH] Filter: quick implementation of negation Add negate buttons to the Tags, People, Location and Equipment filters. Currently, if nothing is entered the filter is ignored whether negate is on or off. One might think about filtering all dives without tags, etc. instead. Signed-off-by: Berthold Stoeger --- desktop-widgets/filterwidget2.cpp | 20 +++++++++-- desktop-widgets/filterwidget2.ui | 59 +++++++++++++++++++++++-------- qt-models/filtermodels.cpp | 30 ++++++++-------- qt-models/filtermodels.h | 5 ++- 4 files changed, 81 insertions(+), 33 deletions(-) diff --git a/desktop-widgets/filterwidget2.cpp b/desktop-widgets/filterwidget2.cpp index c27d22062..71e7de83d 100644 --- a/desktop-widgets/filterwidget2.cpp +++ b/desktop-widgets/filterwidget2.cpp @@ -20,8 +20,8 @@ FilterWidget2::FilterWidget2(QWidget* parent) : QWidget(parent), ignoreSignal(fa // TODO: unhide this when we discover how to search for equipment. ui.equipment->hide(); + ui.equipmentNegate->hide(); ui.labelEquipment->hide(); - ui.invertFilter->hide(); ui.fromDate->setDisplayFormat(prefs.date_format); ui.fromTime->setDisplayFormat(prefs.time_format); @@ -77,12 +77,21 @@ FilterWidget2::FilterWidget2(QWidget* parent) : QWidget(parent), ignoreSignal(fa connect(ui.tags, &QLineEdit::textChanged, this, &FilterWidget2::updateFilter); + connect(ui.tagsNegate, &QToolButton::toggled, + this, &FilterWidget2::updateFilter); + connect(ui.people, &QLineEdit::textChanged, this, &FilterWidget2::updateFilter); + connect(ui.peopleNegate, &QToolButton::toggled, + this, &FilterWidget2::updateFilter); + connect(ui.location, &QLineEdit::textChanged, this, &FilterWidget2::updateFilter); + connect(ui.locationNegate, &QToolButton::toggled, + this, &FilterWidget2::updateFilter); + connect(ui.logged, SIGNAL(stateChanged(int)), this, SLOT(updateLogged(int))); connect(ui.planned, SIGNAL(stateChanged(int)), this, SLOT(updatePlanned(int))); @@ -121,6 +130,10 @@ void FilterWidget2::clearFilter() ui.fromTime->setTime(filterData.fromTime); ui.toDate->setDate(filterData.toDate.date()); ui.toTime->setTime(filterData.toTime); + ui.tagsNegate->setChecked(filterData.tagsNegate); + ui.peopleNegate->setChecked(filterData.peopleNegate); + ui.locationNegate->setChecked(filterData.locationNegate); + ui.equipmentNegate->setChecked(filterData.equipmentNegate); ignoreSignal = false; filterDataChanged(filterData); @@ -162,7 +175,10 @@ void FilterWidget2::updateFilter() filterData.people = ui.people->text().split(",", QString::SkipEmptyParts); filterData.location = ui.location->text().split(",", QString::SkipEmptyParts); filterData.equipment = ui.equipment->text().split(",", QString::SkipEmptyParts); - filterData.invertFilter = ui.invertFilter->isChecked(); + filterData.tagsNegate = ui.tagsNegate->isChecked(); + filterData.peopleNegate = ui.peopleNegate->isChecked(); + filterData.locationNegate = ui.locationNegate->isChecked(); + filterData.equipmentNegate = ui.equipmentNegate->isChecked(); filterData.logged = ui.logged->isChecked(); filterData.planned = ui.planned->isChecked(); diff --git a/desktop-widgets/filterwidget2.ui b/desktop-widgets/filterwidget2.ui index 0822a582f..84c543640 100644 --- a/desktop-widgets/filterwidget2.ui +++ b/desktop-widgets/filterwidget2.ui @@ -21,7 +21,7 @@ - + @@ -62,16 +62,6 @@ - - - - Display dives that will not match the search, only applies to tags, people, location and equipment - - - Invert filter - - - @@ -131,7 +121,7 @@ - + @@ -147,7 +137,7 @@ - + @@ -157,7 +147,7 @@ - + @@ -301,6 +291,46 @@ + + + + ¬ + + + true + + + + + + + ¬ + + + true + + + + + + + ¬ + + + true + + + + + + + ¬ + + + true + + + @@ -326,7 +356,6 @@ people location equipment - invertFilter diff --git a/qt-models/filtermodels.cpp b/qt-models/filtermodels.cpp index 5168e32d8..1a292741a 100644 --- a/qt-models/filtermodels.cpp +++ b/qt-models/filtermodels.cpp @@ -21,31 +21,31 @@ namespace { bool listContainsSuperstring(const QStringList &list, const QString &s) { return std::any_of(list.begin(), list.end(), [&s](const QString &s2) - { return s2.trimmed().contains(s.trimmed(), Qt::CaseInsensitive); }); + { return s2.trimmed().contains(s.trimmed(), Qt::CaseInsensitive); } ); } - bool hasTags(const QStringList &tags, const struct dive *d) + bool hasTags(const QStringList &tags, const struct dive *d, bool negate) { if (tags.isEmpty()) return true; QStringList dive_tags = get_taglist_string(d->tag_list).split(","); - return std::all_of(tags.begin(), tags.end(), [&dive_tags](const QString &tag) - { return listContainsSuperstring(dive_tags, tag); }); + return std::all_of(tags.begin(), tags.end(), [&dive_tags, negate](const QString &tag) + { return listContainsSuperstring(dive_tags, tag) != negate; } ); } - bool hasPersons(const QStringList &people, const struct dive *d) + bool hasPersons(const QStringList &people, const struct dive *d, bool negate) { if (people.isEmpty()) return true; QStringList dive_people = QString(d->buddy).split(",", QString::SkipEmptyParts) + QString(d->divemaster).split(",", QString::SkipEmptyParts); - return std::all_of(people.begin(), people.end(), [&dive_people](const QString &person) - { return listContainsSuperstring(dive_people, person); }); + return std::all_of(people.begin(), people.end(), [&dive_people, negate](const QString &person) + { return listContainsSuperstring(dive_people, person) != negate; } ); } - bool hasLocations(const QStringList &locations, const struct dive *d) + bool hasLocations(const QStringList &locations, const struct dive *d, bool negate) { if (locations.isEmpty()) return true; @@ -56,12 +56,12 @@ namespace { if (d->dive_site) diveLocations.push_back(QString(d->dive_site->name)); - return std::all_of(locations.begin(), locations.end(), [&diveLocations](const QString &location) - { return listContainsSuperstring(diveLocations, location); }); + return std::all_of(locations.begin(), locations.end(), [&diveLocations, negate](const QString &location) + { return listContainsSuperstring(diveLocations, location) != negate; } ); } // TODO: Finish this iimplementation. - bool hasEquipment(const QStringList& equipment, const struct dive *d) + bool hasEquipment(const QStringList &, const struct dive *, bool) { return true; } @@ -129,18 +129,18 @@ bool MultiFilterSortModel::showDive(const struct dive *d) const return false; // tags. - if (!hasTags(filterData.tags, d)) + if (!hasTags(filterData.tags, d, filterData.tagsNegate)) return false; // people - if (!hasPersons(filterData.people, d)) + if (!hasPersons(filterData.people, d, filterData.peopleNegate)) return false; // Location - if (!hasLocations(filterData.location, d)) + if (!hasLocations(filterData.location, d, filterData.locationNegate)) return false; - if (!hasEquipment(filterData.equipment, d)) + if (!hasEquipment(filterData.equipment, d, filterData.equipmentNegate)) return false; // Planned/Logged diff --git a/qt-models/filtermodels.h b/qt-models/filtermodels.h index 7ef50df92..39f6f83e4 100644 --- a/qt-models/filtermodels.h +++ b/qt-models/filtermodels.h @@ -35,9 +35,12 @@ struct FilterData { QStringList people; QStringList location; QStringList equipment; + bool tagsNegate = false; + bool peopleNegate = false; + bool locationNegate = false; + bool equipmentNegate = false; bool logged = true; bool planned = true; - bool invertFilter; }; class MultiFilterSortModel : public QSortFilterProxyModel {