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>
|
||||
</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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue