summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--desktop-widgets/command_divelist.cpp14
-rw-r--r--qt-models/filtermodels.cpp159
-rw-r--r--qt-models/filtermodels.h15
3 files changed, 183 insertions, 5 deletions
diff --git a/desktop-widgets/command_divelist.cpp b/desktop-widgets/command_divelist.cpp
index 057e852c0..1bc225086 100644
--- a/desktop-widgets/command_divelist.cpp
+++ b/desktop-widgets/command_divelist.cpp
@@ -109,6 +109,11 @@ std::vector<DiveToAdd> DiveListBase::removeDives(std::vector<dive *> &divesToDel
std::vector<DiveToAdd> res;
res.reserve(divesToDelete.size());
+ // First, tell the filters that dives are removed. This could
+ // be done later using the emitted signals, but we do this here
+ // for symmetry with addDives()
+ MultiFilterSortModel::instance()->divesDeleted(QVector<dive *>::fromStdVector(divesToDelete));
+
for (dive *d: divesToDelete)
res.push_back(removeDive(d));
divesToDelete.clear();
@@ -141,6 +146,15 @@ std::vector<dive *> DiveListBase::addDives(std::vector<DiveToAdd> &divesToAdd)
std::vector<dive *> res;
res.resize(divesToAdd.size());
+ // First, tell the filters that new dives are added. We do this here
+ // instead of later by signals, so that the filter can set the
+ // checkboxes of the new rows to its liking. The added dives will
+ // then appear in the correct shown/hidden state.
+ QVector<dive *> divesForFilter;
+ for (const DiveToAdd &entry: divesToAdd)
+ divesForFilter.push_back(entry.dive.get());
+ MultiFilterSortModel::instance()->divesAdded(divesForFilter);
+
// At the end of the function, to send the proper dives-added signals,
// we the the list of added trips. Create this list now.
std::vector<dive_trip *> addedTrips;
diff --git a/qt-models/filtermodels.cpp b/qt-models/filtermodels.cpp
index f6ff5ea69..1491dbacf 100644
--- a/qt-models/filtermodels.cpp
+++ b/qt-models/filtermodels.cpp
@@ -4,6 +4,7 @@
#include "core/display.h"
#include "core/qthelper.h"
#include "core/subsurface-string.h"
+#include "core/subsurface-qt/DiveListNotifier.h"
#include "qt-models/divetripmodel.h"
#if !defined(SUBSURFACE_MOBILE)
@@ -159,6 +160,58 @@ void FilterModelBase::updateList(QStringList &newList)
endResetModel();
}
+// Decrease count of entry with given name. Remove if count reaches zero.
+// Exception: Don't remove the "Show Empty Tags" entry.
+void FilterModelBase::decreaseCount(const QString &name)
+{
+ if (name.isEmpty()) {
+ // Decrease the "Show Empty Tags" entry. Keep it even if count reaches 0.
+ if (items.empty() || items.back().count <= 0)
+ return; // Shouldn't happen!
+ --items.back().count;
+ int idx = items.size() - 1;
+ dataChanged(createIndex(idx, 0), createIndex(idx, 0));
+ return;
+ }
+
+ int idx = indexOf(name);
+ if (idx < 0 || items[idx].count <= 0)
+ return; // Shouldn't happen
+
+ if(--items[idx].count == 0) {
+ beginRemoveRows(QModelIndex(), idx, idx);
+ items.erase(items.begin() + idx);
+ endRemoveRows();
+ } else {
+ dataChanged(createIndex(idx, 0), createIndex(idx, 0));
+ }
+}
+
+// Increase count of entry with given name. If entry doesn't yet exist, add it.
+void FilterModelBase::increaseCount(const QString &name)
+{
+ if (name.isEmpty()) {
+ // Increase the "Show Empty Tags" entry. Keep it even if count reaches 0.
+ if (items.empty())
+ return; // Shouldn't happen!
+ ++items.back().count;
+ int idx = items.size() - 1;
+ dataChanged(createIndex(idx, 0), createIndex(idx, 0));
+ return;
+ }
+
+ int idx = indexOf(name);
+ if (idx < 0) {
+ idx = findInsertionIndex(name);
+ beginInsertRows(QModelIndex(), idx, idx);
+ items.insert(items.begin() + idx, { name, anyChecked, 1 });
+ endInsertRows();
+ } else {
+ ++items[idx].count;
+ dataChanged(createIndex(idx, 0), createIndex(idx, 0));
+ }
+}
+
Qt::ItemFlags FilterModelBase::flags(const QModelIndex &index) const
{
return QAbstractListModel::flags(index) | Qt::ItemIsUserCheckable;
@@ -258,6 +311,16 @@ bool SuitsFilterModel::doFilter(const dive *d) const
return negate;
}
+void SuitsFilterModel::diveAdded(const dive *d)
+{
+ increaseCount(QString(d->suit));
+}
+
+void SuitsFilterModel::diveDeleted(const dive *d)
+{
+ decreaseCount(QString(d->suit));
+}
+
void SuitsFilterModel::repopulate()
{
QStringList list;
@@ -322,6 +385,33 @@ bool TagFilterModel::doFilter(const dive *d) const
return negate;
}
+void TagFilterModel::diveAdded(const dive *d)
+{
+ struct tag_entry *head = d->tag_list;
+ if (!head) {
+ increaseCount(QString());
+ return;
+ }
+ while (head) {
+ increaseCount(QString());
+ increaseCount(QString(head->tag->name));
+ head = head->next;
+ }
+}
+
+void TagFilterModel::diveDeleted(const dive *d)
+{
+ struct tag_entry *head = d->tag_list;
+ if (!head) {
+ decreaseCount(QString());
+ return;
+ }
+ while (head) {
+ decreaseCount(QString(head->tag->name));
+ head = head->next;
+ }
+}
+
BuddyFilterModel::BuddyFilterModel(QObject *parent) : FilterModelBase(parent)
{
}
@@ -331,6 +421,15 @@ int BuddyFilterModel::countDives(const char *s) const
return count_dives_with_person(s);
}
+static QStringList getDiveBuddies(const dive *d)
+{
+ QString persons = QString(d->buddy) + "," + QString(d->divemaster);
+ QStringList personsList = persons.split(',', QString::SkipEmptyParts);
+ for (QString &s: personsList)
+ s = s.trimmed();
+ return personsList;
+}
+
bool BuddyFilterModel::doFilter(const dive *d) const
{
// If there's nothing checked, this should show everything
@@ -339,11 +438,7 @@ bool BuddyFilterModel::doFilter(const dive *d) const
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();
+ QStringList personsList = getDiveBuddies(d);
// only show empty buddie dives if the user checked that.
if (personsList.isEmpty())
return items[rowCount() - 1].checked != negate;
@@ -357,6 +452,28 @@ bool BuddyFilterModel::doFilter(const dive *d) const
return negate;
}
+void BuddyFilterModel::diveAdded(const dive *d)
+{
+ QStringList buddies = getDiveBuddies(d);
+ if (buddies.empty()) {
+ increaseCount(QString());
+ return;
+ }
+ for(const QString &buddy: buddies)
+ increaseCount(buddy);
+}
+
+void BuddyFilterModel::diveDeleted(const dive *d)
+{
+ QStringList buddies = getDiveBuddies(d);
+ if (buddies.empty()) {
+ decreaseCount(QString());
+ return;
+ }
+ for(const QString &buddy: buddies)
+ decreaseCount(buddy);
+}
+
void BuddyFilterModel::repopulate()
{
QStringList list;
@@ -406,6 +523,16 @@ bool LocationFilterModel::doFilter(const dive *d) const
return negate;
}
+void LocationFilterModel::diveAdded(const dive *d)
+{
+ increaseCount(get_dive_location(d));
+}
+
+void LocationFilterModel::diveDeleted(const dive *d)
+{
+ decreaseCount(get_dive_location(d));
+}
+
void LocationFilterModel::repopulate()
{
QStringList list;
@@ -437,6 +564,28 @@ MultiFilterSortModel::MultiFilterSortModel(QObject *parent) : QSortFilterProxyMo
{
}
+void MultiFilterSortModel::divesAdded(const QVector<dive *> &dives)
+{
+ // TODO: We call diveAdded for every dive and model.
+ // If multiple dives are added (e.g. import dive) this will lead to a large
+ // number of model changes and might be a pessimization compared to a full
+ // model reload. Instead, the models should take the vector, calculate the
+ // new fields and add them at once.
+ for (FilterModelBase *model: models) {
+ for (const dive *d: dives)
+ model->diveAdded(d);
+ }
+}
+
+void MultiFilterSortModel::divesDeleted(const QVector<dive *> &dives)
+{
+ // TODO: See comment for divesDeleted
+ for (FilterModelBase *model: models) {
+ for (const dive *d: dives)
+ model->diveDeleted(d);
+ }
+}
+
bool MultiFilterSortModel::showDive(const struct dive *d) const
{
if (curr_dive_site) {
diff --git a/qt-models/filtermodels.h b/qt-models/filtermodels.h
index 08e99fd93..3f5ca5f01 100644
--- a/qt-models/filtermodels.h
+++ b/qt-models/filtermodels.h
@@ -8,6 +8,7 @@
#include <vector>
struct dive;
+struct dive_trip;
class FilterModelBase : public QAbstractListModel {
Q_OBJECT
@@ -23,8 +24,12 @@ protected:
int indexOf(const QString &name) const;
void addItem(const QString &name, bool checked, int count);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ void decreaseCount(const QString &d);
+ void increaseCount(const QString &d);
public:
virtual bool doFilter(const dive *d) const = 0;
+ virtual void diveAdded(const dive *d) = 0;
+ virtual void diveDeleted(const dive *d) = 0;
void clearFilter();
void selectAll();
void invertSelection();
@@ -56,6 +61,8 @@ slots:
private:
explicit TagFilterModel(QObject *parent = 0);
int countDives(const char *) const;
+ void diveAdded(const dive *d);
+ void diveDeleted(const dive *d);
};
class BuddyFilterModel : public FilterModelBase {
@@ -70,6 +77,8 @@ slots:
private:
explicit BuddyFilterModel(QObject *parent = 0);
int countDives(const char *) const;
+ void diveAdded(const dive *d);
+ void diveDeleted(const dive *d);
};
class LocationFilterModel : public FilterModelBase {
@@ -85,6 +94,8 @@ slots:
private:
explicit LocationFilterModel(QObject *parent = 0);
int countDives(const char *) const;
+ void diveAdded(const dive *d);
+ void diveDeleted(const dive *d);
};
class SuitsFilterModel : public FilterModelBase {
@@ -99,6 +110,8 @@ slots:
private:
explicit SuitsFilterModel(QObject *parent = 0);
int countDives(const char *) const;
+ void diveAdded(const dive *d);
+ void diveDeleted(const dive *d);
};
class MultiFilterSortModel : public QSortFilterProxyModel {
@@ -108,6 +121,8 @@ public:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
void addFilterModel(FilterModelBase *model);
void removeFilterModel(FilterModelBase *model);
+ void divesAdded(const QVector<dive *> &dives);
+ void divesDeleted(const QVector<dive *> &dives);
bool showDive(const struct dive *d) const;
int divesDisplayed;
public