summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2017-12-24 14:35:59 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2017-12-26 13:08:49 -0800
commitb6bf57a13b5e4d3dd469b0fa8790d341eb4f1304 (patch)
treee57922eee99f54276adec54d4f277c8f26e1d1ab
parentb86c70ab2ce91c46355a71008334aa6743caa1e6 (diff)
downloadsubsurface-b6bf57a13b5e4d3dd469b0fa8790d341eb4f1304.tar.gz
Introduce negate-toggle buttons to filter lists
Introduce toggle buttons which mean "filter all dives except those fulfilling the selected criteria". The old code used to check for rowCount() == 0. This should never happen, because there is always a row "empty field". This check was moved into the preamble of the functions to seperate it from the actual logic. Fixes #435 Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r--desktop-widgets/listfilter.ui10
-rw-r--r--desktop-widgets/simplewidgets.cpp1
-rw-r--r--qt-models/filtermodels.cpp80
-rw-r--r--qt-models/filtermodels.h5
4 files changed, 55 insertions, 41 deletions
diff --git a/desktop-widgets/listfilter.ui b/desktop-widgets/listfilter.ui
index 48d813d21..b1d717bf0 100644
--- a/desktop-widgets/listfilter.ui
+++ b/desktop-widgets/listfilter.ui
@@ -51,6 +51,16 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QToolButton" name="notButton">
+ <property name="text">
+ <string>¬</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
diff --git a/desktop-widgets/simplewidgets.cpp b/desktop-widgets/simplewidgets.cpp
index b63349819..f8cd96943 100644
--- a/desktop-widgets/simplewidgets.cpp
+++ b/desktop-widgets/simplewidgets.cpp
@@ -516,6 +516,7 @@ FilterBase::FilterBase(FilterModelBase *model_, QWidget *parent) : QWidget(paren
filter->setSourceModel(model);
filter->setFilterCaseSensitivity(Qt::CaseInsensitive);
connect(ui.filterInternalList, SIGNAL(textChanged(QString)), filter, SLOT(setFilterFixedString(QString)));
+ connect(ui.notButton, &QToolButton::toggled, model, &FilterModelBase::setNegate);
ui.filterList->setModel(filter);
addContextMenuEntry(tr("Select All"), &FilterModelBase::selectAll);
diff --git a/qt-models/filtermodels.cpp b/qt-models/filtermodels.cpp
index 004ff8493..48a2fd9b9 100644
--- a/qt-models/filtermodels.cpp
+++ b/qt-models/filtermodels.cpp
@@ -26,7 +26,8 @@ CREATE_INSTANCE_METHOD(SuitsFilterModel)
CREATE_INSTANCE_METHOD(MultiFilterSortModel)
FilterModelBase::FilterModelBase(QObject *parent) : QStringListModel(parent),
- anyChecked(false)
+ anyChecked(false),
+ negate(false)
{
}
@@ -115,6 +116,12 @@ void FilterModelBase::invertSelection()
emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0));
}
+void FilterModelBase::setNegate(bool negateParam)
+{
+ negate = negateParam;
+ emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0));
+}
+
SuitsFilterModel::SuitsFilterModel(QObject *parent) : FilterModelBase(parent)
{
}
@@ -129,28 +136,25 @@ bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel
Q_UNUSED(index0);
Q_UNUSED(sourceModel);
- if (!anyChecked) {
+ // rowCount() == 0 should never happen, because we have the "no suits" row
+ // let's handle it gracefully anyway.
+ if (!anyChecked || rowCount() == 0)
return true;
- }
// Checked means 'Show', Unchecked means 'Hide'.
QString suit(d->suit);
// only show empty suit dives if the user checked that.
- if (suit.isEmpty()) {
- if (rowCount() > 0)
- return checkState[rowCount() - 1];
- else
- return true;
- }
+ if (suit.isEmpty())
+ return checkState[rowCount() - 1] != negate;
// there is a suit selected
QStringList suitList = stringList();
// Ignore last item, since this is the "Show Empty Tags" entry
for (int i = 0; i < rowCount() - 1; i++) {
if (checkState[i] && suit == suitList[i])
- return true;
+ return !negate;
}
- return false;
+ return negate;
}
void SuitsFilterModel::repopulate()
@@ -200,18 +204,16 @@ bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *
Q_UNUSED(sourceModel);
// If there's nothing checked, this should show everything
- if (!anyChecked) {
+ // rowCount() == 0 should never happen, because we have the "no tags" row
+ // let's handle it gracefully anyway.
+ if (!anyChecked || rowCount() == 0)
return true;
- }
+
// Checked means 'Show', Unchecked means 'Hide'.
struct tag_entry *head = d->tag_list;
- if (!head) { // last tag means "Show empty tags";
- if (rowCount() > 0)
- return checkState[rowCount() - 1];
- else
- return true;
- }
+ if (!head) // last tag means "Show empty tags";
+ return checkState[rowCount() - 1] != negate;
// have at least one tag.
QStringList tagList = stringList();
@@ -221,11 +223,11 @@ bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *
QString tagName(head->tag->name);
int index = tagList.indexOf(tagName);
if (checkState[index])
- return true;
+ return !negate;
head = head->next;
}
}
- return false;
+ return negate;
}
BuddyFilterModel::BuddyFilterModel(QObject *parent) : FilterModelBase(parent)
@@ -243,30 +245,28 @@ bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel
Q_UNUSED(sourceModel);
// If there's nothing checked, this should show everything
- if (!anyChecked) {
+ // rowCount() == 0 should never happen, because we have the "no tags" row
+ // let's handle it gracefully anyway.
+ if (!anyChecked || rowCount() == 0)
return true;
- }
+
// Checked means 'Show', Unchecked means 'Hide'.
QString persons = QString(d->buddy) + "," + QString(d->divemaster);
QStringList personsList = persons.split(',', QString::SkipEmptyParts);
for (QString &s : personsList)
s = s.trimmed();
// only show empty buddie dives if the user checked that.
- if (personsList.isEmpty()) {
- if (rowCount() > 0)
- return checkState[rowCount() - 1];
- else
- return true;
- }
+ if (personsList.isEmpty())
+ return checkState[rowCount() - 1] != negate;
// have at least one buddy
QStringList buddyList = stringList();
// Ignore last item, since this is the "Show Empty Tags" entry
for (int i = 0; i < rowCount() - 1; i++) {
if (checkState[i] && personsList.contains(buddyList[i], Qt::CaseInsensitive))
- return true;
+ return !negate;
}
- return false;
+ return negate;
}
void BuddyFilterModel::repopulate()
@@ -302,27 +302,25 @@ bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstrac
Q_UNUSED(index0);
Q_UNUSED(sourceModel);
- if (!anyChecked) {
+ // rowCount() == 0 should never happen, because we have the "no location" row
+ // let's handle it gracefully anyway.
+ if (!anyChecked || rowCount() == 0)
return true;
- }
+
// Checked means 'Show', Unchecked means 'Hide'.
QString location(get_dive_location(d));
// only show empty location dives if the user checked that.
- if (location.isEmpty()) {
- if (rowCount() > 0)
- return checkState[rowCount() - 1];
- else
- return true;
- }
+ if (location.isEmpty())
+ return checkState[rowCount() - 1] != negate;
// There is a location selected
QStringList locationList = stringList();
// Ignore last item, since this is the "Show Empty Tags" entry
for (int i = 0; i < rowCount() - 1; i++) {
if (checkState[i] && location == locationList[i])
- return true;
+ return !negate;
}
- return false;
+ return negate;
}
void LocationFilterModel::repopulate()
diff --git a/qt-models/filtermodels.h b/qt-models/filtermodels.h
index 9db5e5a97..b866b68b2 100644
--- a/qt-models/filtermodels.h
+++ b/qt-models/filtermodels.h
@@ -8,6 +8,7 @@
#include <vector>
class FilterModelBase : public QStringListModel {
+ Q_OBJECT
public:
virtual bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const = 0;
void clearFilter();
@@ -15,6 +16,10 @@ public:
void invertSelection();
std::vector<char> checkState;
bool anyChecked;
+ bool negate;
+public
+slots:
+ void setNegate(bool negate);
protected:
explicit FilterModelBase(QObject *parent = 0);
void updateList(const QStringList &new_list);