mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
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>
This commit is contained in:
parent
b86c70ab2c
commit
b6bf57a13b
4 changed files with 55 additions and 41 deletions
|
@ -51,6 +51,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="notButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>¬</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|
|
@ -516,6 +516,7 @@ FilterBase::FilterBase(FilterModelBase *model_, QWidget *parent) : QWidget(paren
|
||||||
filter->setSourceModel(model);
|
filter->setSourceModel(model);
|
||||||
filter->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
filter->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
connect(ui.filterInternalList, SIGNAL(textChanged(QString)), filter, SLOT(setFilterFixedString(QString)));
|
connect(ui.filterInternalList, SIGNAL(textChanged(QString)), filter, SLOT(setFilterFixedString(QString)));
|
||||||
|
connect(ui.notButton, &QToolButton::toggled, model, &FilterModelBase::setNegate);
|
||||||
ui.filterList->setModel(filter);
|
ui.filterList->setModel(filter);
|
||||||
|
|
||||||
addContextMenuEntry(tr("Select All"), &FilterModelBase::selectAll);
|
addContextMenuEntry(tr("Select All"), &FilterModelBase::selectAll);
|
||||||
|
|
|
@ -26,7 +26,8 @@ CREATE_INSTANCE_METHOD(SuitsFilterModel)
|
||||||
CREATE_INSTANCE_METHOD(MultiFilterSortModel)
|
CREATE_INSTANCE_METHOD(MultiFilterSortModel)
|
||||||
|
|
||||||
FilterModelBase::FilterModelBase(QObject *parent) : QStringListModel(parent),
|
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));
|
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)
|
SuitsFilterModel::SuitsFilterModel(QObject *parent) : FilterModelBase(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -129,28 +136,25 @@ bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel
|
||||||
Q_UNUSED(index0);
|
Q_UNUSED(index0);
|
||||||
Q_UNUSED(sourceModel);
|
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;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// Checked means 'Show', Unchecked means 'Hide'.
|
// Checked means 'Show', Unchecked means 'Hide'.
|
||||||
QString suit(d->suit);
|
QString suit(d->suit);
|
||||||
// only show empty suit dives if the user checked that.
|
// only show empty suit dives if the user checked that.
|
||||||
if (suit.isEmpty()) {
|
if (suit.isEmpty())
|
||||||
if (rowCount() > 0)
|
return checkState[rowCount() - 1] != negate;
|
||||||
return checkState[rowCount() - 1];
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// there is a suit selected
|
// there is a suit selected
|
||||||
QStringList suitList = stringList();
|
QStringList suitList = stringList();
|
||||||
// Ignore last item, since this is the "Show Empty Tags" entry
|
// Ignore last item, since this is the "Show Empty Tags" entry
|
||||||
for (int i = 0; i < rowCount() - 1; i++) {
|
for (int i = 0; i < rowCount() - 1; i++) {
|
||||||
if (checkState[i] && suit == suitList[i])
|
if (checkState[i] && suit == suitList[i])
|
||||||
return true;
|
return !negate;
|
||||||
}
|
}
|
||||||
return false;
|
return negate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuitsFilterModel::repopulate()
|
void SuitsFilterModel::repopulate()
|
||||||
|
@ -200,18 +204,16 @@ bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *
|
||||||
Q_UNUSED(sourceModel);
|
Q_UNUSED(sourceModel);
|
||||||
|
|
||||||
// If there's nothing checked, this should show everything
|
// 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;
|
return true;
|
||||||
}
|
|
||||||
// Checked means 'Show', Unchecked means 'Hide'.
|
// Checked means 'Show', Unchecked means 'Hide'.
|
||||||
struct tag_entry *head = d->tag_list;
|
struct tag_entry *head = d->tag_list;
|
||||||
|
|
||||||
if (!head) { // last tag means "Show empty tags";
|
if (!head) // last tag means "Show empty tags";
|
||||||
if (rowCount() > 0)
|
return checkState[rowCount() - 1] != negate;
|
||||||
return checkState[rowCount() - 1];
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// have at least one tag.
|
// have at least one tag.
|
||||||
QStringList tagList = stringList();
|
QStringList tagList = stringList();
|
||||||
|
@ -221,11 +223,11 @@ bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *
|
||||||
QString tagName(head->tag->name);
|
QString tagName(head->tag->name);
|
||||||
int index = tagList.indexOf(tagName);
|
int index = tagList.indexOf(tagName);
|
||||||
if (checkState[index])
|
if (checkState[index])
|
||||||
return true;
|
return !negate;
|
||||||
head = head->next;
|
head = head->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return negate;
|
||||||
}
|
}
|
||||||
|
|
||||||
BuddyFilterModel::BuddyFilterModel(QObject *parent) : FilterModelBase(parent)
|
BuddyFilterModel::BuddyFilterModel(QObject *parent) : FilterModelBase(parent)
|
||||||
|
@ -243,30 +245,28 @@ bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel
|
||||||
Q_UNUSED(sourceModel);
|
Q_UNUSED(sourceModel);
|
||||||
|
|
||||||
// If there's nothing checked, this should show everything
|
// 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;
|
return true;
|
||||||
}
|
|
||||||
// Checked means 'Show', Unchecked means 'Hide'.
|
// Checked means 'Show', Unchecked means 'Hide'.
|
||||||
QString persons = QString(d->buddy) + "," + QString(d->divemaster);
|
QString persons = QString(d->buddy) + "," + QString(d->divemaster);
|
||||||
QStringList personsList = persons.split(',', QString::SkipEmptyParts);
|
QStringList personsList = persons.split(',', QString::SkipEmptyParts);
|
||||||
for (QString &s : personsList)
|
for (QString &s : personsList)
|
||||||
s = s.trimmed();
|
s = s.trimmed();
|
||||||
// only show empty buddie dives if the user checked that.
|
// only show empty buddie dives if the user checked that.
|
||||||
if (personsList.isEmpty()) {
|
if (personsList.isEmpty())
|
||||||
if (rowCount() > 0)
|
return checkState[rowCount() - 1] != negate;
|
||||||
return checkState[rowCount() - 1];
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// have at least one buddy
|
// have at least one buddy
|
||||||
QStringList buddyList = stringList();
|
QStringList buddyList = stringList();
|
||||||
// Ignore last item, since this is the "Show Empty Tags" entry
|
// Ignore last item, since this is the "Show Empty Tags" entry
|
||||||
for (int i = 0; i < rowCount() - 1; i++) {
|
for (int i = 0; i < rowCount() - 1; i++) {
|
||||||
if (checkState[i] && personsList.contains(buddyList[i], Qt::CaseInsensitive))
|
if (checkState[i] && personsList.contains(buddyList[i], Qt::CaseInsensitive))
|
||||||
return true;
|
return !negate;
|
||||||
}
|
}
|
||||||
return false;
|
return negate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuddyFilterModel::repopulate()
|
void BuddyFilterModel::repopulate()
|
||||||
|
@ -302,27 +302,25 @@ bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstrac
|
||||||
Q_UNUSED(index0);
|
Q_UNUSED(index0);
|
||||||
Q_UNUSED(sourceModel);
|
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;
|
return true;
|
||||||
}
|
|
||||||
// Checked means 'Show', Unchecked means 'Hide'.
|
// Checked means 'Show', Unchecked means 'Hide'.
|
||||||
QString location(get_dive_location(d));
|
QString location(get_dive_location(d));
|
||||||
// only show empty location dives if the user checked that.
|
// only show empty location dives if the user checked that.
|
||||||
if (location.isEmpty()) {
|
if (location.isEmpty())
|
||||||
if (rowCount() > 0)
|
return checkState[rowCount() - 1] != negate;
|
||||||
return checkState[rowCount() - 1];
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is a location selected
|
// There is a location selected
|
||||||
QStringList locationList = stringList();
|
QStringList locationList = stringList();
|
||||||
// Ignore last item, since this is the "Show Empty Tags" entry
|
// Ignore last item, since this is the "Show Empty Tags" entry
|
||||||
for (int i = 0; i < rowCount() - 1; i++) {
|
for (int i = 0; i < rowCount() - 1; i++) {
|
||||||
if (checkState[i] && location == locationList[i])
|
if (checkState[i] && location == locationList[i])
|
||||||
return true;
|
return !negate;
|
||||||
}
|
}
|
||||||
return false;
|
return negate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocationFilterModel::repopulate()
|
void LocationFilterModel::repopulate()
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class FilterModelBase : public QStringListModel {
|
class FilterModelBase : public QStringListModel {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
virtual bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const = 0;
|
virtual bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const = 0;
|
||||||
void clearFilter();
|
void clearFilter();
|
||||||
|
@ -15,6 +16,10 @@ public:
|
||||||
void invertSelection();
|
void invertSelection();
|
||||||
std::vector<char> checkState;
|
std::vector<char> checkState;
|
||||||
bool anyChecked;
|
bool anyChecked;
|
||||||
|
bool negate;
|
||||||
|
public
|
||||||
|
slots:
|
||||||
|
void setNegate(bool negate);
|
||||||
protected:
|
protected:
|
||||||
explicit FilterModelBase(QObject *parent = 0);
|
explicit FilterModelBase(QObject *parent = 0);
|
||||||
void updateList(const QStringList &new_list);
|
void updateList(const QStringList &new_list);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue