Plus some bugfixes / cleanups.
From babec5122ddc81facbfe7471dd27b446ab8b2b66 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 16:31:03 -0200
Subject: [PATCH 01/16] Move the filters code to it's own file.

We already have a bunch of filters, let's pack them together

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 CMakeLists.txt          |   1 +
 qt-ui/divelistview.cpp  |   1 +
 qt-ui/filtermodels.cpp  | 470 ++++++++++++++++++++++++++++++++++++++++++++++++
 qt-ui/filtermodels.h    |  87 +++++++++
 qt-ui/mainwindow.cpp    |   1 +
 qt-ui/models.cpp        | 465 -----------------------------------------------
 qt-ui/models.h          |  80 ---------
 qt-ui/simplewidgets.cpp |   1 +
 subsurface.pro          |   6 +-
 9 files changed, 565 insertions(+), 547 deletions(-)
 create mode 100644 qt-ui/filtermodels.cpp
 create mode 100644 qt-ui/filtermodels.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 868ad4f..c93b5fd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -150,6 +150,7 @@ SET(SUBSURFACE_INTERFACE
 	qt-ui/divepicturewidget.cpp
 	qt-ui/usersurvey.cpp
 	qt-ui/configuredivecomputerdialog.cpp
+	qt-ui/filtermodels.cpp
 )
 
 #the profile widget
diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index f250e90..c5ffaaa 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -6,6 +6,7 @@
  */
 #include "divelistview.h"
 #include "models.h"
+#include "filtermodels.h"
 #include "modeldelegates.h"
 #include "mainwindow.h"
 #include "subsurfacewebservices.h"
diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
new file mode 100644
index 0000000..3dabc80
--- /dev/null
+++ b/qt-ui/filtermodels.cpp
@@ -0,0 +1,470 @@
+#include "filtermodels.h"
+#include "dive.h"
+#include "models.h"
+#include "mainwindow.h"
+#include "display.h"
+
+TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
+{
+}
+
+TagFilterModel *TagFilterModel::instance()
+{
+	static TagFilterModel *self = new TagFilterModel();
+	return self;
+}
+
+QVariant TagFilterModel::data(const QModelIndex &index, int role) const
+{
+	if (role == Qt::CheckStateRole) {
+		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
+	} else if (role == Qt::DisplayRole) {
+		QString tag = stringList()[index.row()];
+		int count = count_dives_with_tag(tag.toUtf8().data());
+		return tag + QString(" (%1)").arg(count);
+	}
+	return QVariant();
+}
+
+Qt::ItemFlags TagFilterModel::flags(const QModelIndex &index) const
+{
+	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
+}
+
+void TagFilterModel::repopulate()
+{
+	if (g_tag_list == NULL)
+		return;
+	QStringList list;
+	struct tag_entry *current_tag_entry = g_tag_list->next;
+	while (current_tag_entry != NULL) {
+		list.append(QString(current_tag_entry->tag->name));
+		current_tag_entry = current_tag_entry->next;
+	}
+	qSort(list);
+	list << tr("Empty Tags");
+	setStringList(list);
+	delete[] checkState;
+	checkState = new bool[list.count()];
+	memset(checkState, false, list.count());
+	checkState[list.count() - 1] = false;
+	anyChecked = false;
+}
+
+bool TagFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+	if (role == Qt::CheckStateRole) {
+		checkState[index.row()] = value.toBool();
+		anyChecked = false;
+		for (int i = 0; i < rowCount(); i++) {
+			if (checkState[i] == true) {
+				anyChecked = true;
+				break;
+			}
+		}
+		dataChanged(index, index);
+		return true;
+	}
+	return false;
+}
+
+bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
+{
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
+	if (!d) { // It's a trip, only show the ones that have dives to be shown.
+		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
+			if (filterRow(i, index0, sourceModel))
+				return true;
+		}
+		return false;
+	}
+	// 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;
+	}
+
+	// have at least one tag.
+	QStringList tagList = stringList();
+	if (!tagList.isEmpty()) {
+		tagList.removeLast(); // remove the "Show Empty Tags";
+		while (head) {
+			QString tagName(head->tag->name);
+			int index = tagList.indexOf(tagName);
+			if (checkState[index])
+				return true;
+			head = head->next;
+		}
+	}
+	return false;
+}
+
+bool TagFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
+{
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
+
+	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
+	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
+	struct dive *d = (struct dive *)diveVariant.value<void *>();
+
+	bool show = doFilter(d, index0, sourceModel);
+	filter_dive(d, show);
+	return show;
+}
+
+BuddyFilterModel::BuddyFilterModel(QObject *parent) : QStringListModel(parent)
+{
+}
+
+BuddyFilterModel *BuddyFilterModel::instance()
+{
+	static BuddyFilterModel *self = new BuddyFilterModel();
+	return self;
+}
+
+bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
+{
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
+	if (!d) { // It's a trip, only show the ones that have dives to be shown.
+		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
+			if (filterRow(i, index0, sourceModel))
+				return true;
+		}
+		return false;
+	}
+
+	// Checked means 'Show', Unchecked means 'Hide'.
+	QString diveBuddy(d->buddy);
+	QString divemaster(d->divemaster);
+	// only show empty buddie dives if the user checked that.
+	if (diveBuddy.isEmpty() && divemaster.isEmpty()) {
+		if (rowCount() > 0)
+			return checkState[rowCount() - 1];
+		else
+			return true;
+	}
+
+	// have at least one buddy
+	QStringList buddyList = stringList();
+	if (!buddyList.isEmpty()) {
+		buddyList.removeLast(); // remove the "Show Empty Tags";
+		for (int i = 0; i < rowCount(); i++) {
+			if (checkState[i] && (diveBuddy.indexOf(stringList()[i]) != -1 || divemaster.indexOf(stringList()[i]) != -1)) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+bool BuddyFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
+{
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
+
+	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
+	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
+	struct dive *d = (struct dive *)diveVariant.value<void *>();
+
+	return doFilter(d, index0, sourceModel);
+}
+
+Qt::ItemFlags BuddyFilterModel::flags(const QModelIndex &index) const
+{
+	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
+}
+
+void BuddyFilterModel::repopulate()
+{
+	QStringList list;
+	struct dive *dive;
+	int i = 0;
+	for_each_dive (i, dive) {
+		QString persons = QString(dive->buddy) + "," + QString(dive->divemaster);
+		Q_FOREACH(const QString& person, persons.split(',', QString::SkipEmptyParts)){
+			// Remove any leading spaces
+			if (!list.contains(person.trimmed())) {
+				list.append(person.trimmed());
+			}
+		}
+	}
+	qSort(list);
+	list << tr("No buddies");
+	setStringList(list);
+	delete[] checkState;
+	checkState = new bool[list.count()];
+	memset(checkState, false, list.count());
+	checkState[list.count() - 1] = false;
+	anyChecked = false;
+}
+
+QVariant BuddyFilterModel::data(const QModelIndex &index, int role) const
+{
+	if (role == Qt::CheckStateRole) {
+		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
+	} else if (role == Qt::DisplayRole) {
+		QString person = stringList()[index.row()];
+		int count = count_dives_with_person(person.toUtf8().data());
+		return person + QString(" (%1)").arg(count);
+	}
+	return QVariant();
+}
+
+
+bool BuddyFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+	if (role == Qt::CheckStateRole) {
+		checkState[index.row()] = value.toBool();
+		anyChecked = false;
+		for (int i = 0; i < rowCount(); i++) {
+			if (checkState[i] == true) {
+				anyChecked = true;
+				break;
+			}
+		}
+		dataChanged(index, index);
+		return true;
+	}
+	return false;
+}
+
+LocationFilterModel::LocationFilterModel(QObject *parent) : QStringListModel(parent)
+{
+}
+
+QVariant LocationFilterModel::data(const QModelIndex &index, int role) const
+{
+	if (role == Qt::CheckStateRole) {
+		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
+	} else if (role == Qt::DisplayRole) {
+		QString location = stringList()[index.row()];
+		int count = count_dives_with_location(location.toUtf8().data());
+		return location + QString(" (%1)").arg(count);
+	}
+	return QVariant();
+}
+
+bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
+{
+	if (!anyChecked) {
+		return true;
+	}
+
+	if (!d) { // It's a trip, only show the ones that have dives to be shown.
+		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
+			if (filterRow(i, index0, sourceModel))
+				return true;
+		}
+		return false;
+	}
+
+	// Checked means 'Show', Unchecked means 'Hide'.
+	QString location(d->location);
+	// only show empty location dives if the user checked that.
+	if (location.isEmpty()) {
+		if (rowCount() > 0)
+			return checkState[rowCount() - 1];
+		else
+			return true;
+	}
+
+	// there is a location selected
+	QStringList locationList = stringList();
+	if (!locationList.isEmpty()) {
+		locationList.removeLast(); // remove the "Show Empty Tags";
+		for (int i = 0; i < rowCount(); i++) {
+			if (checkState[i] && (location.indexOf(stringList()[i]) != -1)) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+bool LocationFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
+{
+
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
+
+	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
+	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
+	struct dive *d = (struct dive *)diveVariant.value<void *>();
+
+	return doFilter(d, index0, sourceModel);
+}
+
+Qt::ItemFlags LocationFilterModel::flags(const QModelIndex &index) const
+{
+	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
+}
+
+LocationFilterModel *LocationFilterModel::instance()
+{
+	static LocationFilterModel *self = new LocationFilterModel();
+	return self;
+}
+
+void LocationFilterModel::repopulate()
+{
+	QStringList list;
+	struct dive *dive;
+	int i = 0;
+	for_each_dive (i, dive) {
+		QString location(dive->location);
+		if (!location.isEmpty() && !list.contains(location)) {
+			list.append(location);
+		}
+	}
+	qSort(list);
+	list << tr("No location set");
+	setStringList(list);
+	delete[] checkState;
+	checkState = new bool[list.count()];
+	memset(checkState, false, list.count());
+	checkState[list.count() - 1] = false;
+	anyChecked = false;
+}
+
+bool LocationFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+	if (role == Qt::CheckStateRole) {
+		checkState[index.row()] = value.toBool();
+		anyChecked = false;
+		for (int i = 0; i < rowCount(); i++) {
+			if (checkState[i] == true) {
+				anyChecked = true;
+				break;
+			}
+		}
+		dataChanged(index, index);
+		return true;
+	}
+	return false;
+}
+
+MultiFilterSortModel *MultiFilterSortModel::instance()
+{
+	static MultiFilterSortModel *self = new MultiFilterSortModel();
+	return self;
+}
+
+MultiFilterSortModel::MultiFilterSortModel(QObject *parent) : QSortFilterProxyModel(parent), justCleared(false)
+{
+}
+
+bool MultiFilterSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
+{
+	if (justCleared || models.isEmpty())
+		return true;
+
+	bool shouldShow = true;
+	QModelIndex index0 = sourceModel()->index(source_row, 0, source_parent);
+	QVariant diveVariant = sourceModel()->data(index0, DiveTripModel::DIVE_ROLE);
+	struct dive *d = (struct dive *)diveVariant.value<void *>();
+
+	Q_FOREACH (MultiFilterInterface *model, models) {
+		if (!model->doFilter(d, index0, sourceModel()))
+			shouldShow = false;
+	}
+	// if it's a dive, mark it accordingly
+	filter_dive(d, shouldShow);
+	return shouldShow;
+}
+
+void MultiFilterSortModel::myInvalidate()
+{
+	int i;
+	struct dive *d;
+	DiveListView *dlv = MainWindow::instance()->dive_list();
+
+	invalidate();
+	// first make sure the trips are no longer shown as selected
+	// (but without updating the selection state of the dives... this just cleans
+	//  up an oddity in the filter handling)
+	// TODO: This should go internally to DiveList, to be triggered after a filter is due.
+	dlv->clearTripSelection();
+
+	// if we have no more selected dives, clean up the display - this later triggers us
+	// to pick one of the dives that are shown in the list as selected dive which is the
+	// natural behavior
+	if (amount_selected == 0) {
+		MainWindow::instance()->cleanUpEmpty();
+	} else {
+		// otherwise find the dives that should still be selected (the filter above unselected any
+		// dive that's no longer visible) and select them again
+		QList<int>curSelectedDives;
+		for_each_dive (i, d) {
+			if(d->selected)
+				curSelectedDives.append(get_divenr(d));
+		}
+		dlv->selectDives(curSelectedDives);
+	}
+}
+
+void MultiFilterSortModel::addFilterModel(MultiFilterInterface *model)
+{
+	QAbstractItemModel *itemModel = dynamic_cast<QAbstractItemModel *>(model);
+	Q_ASSERT(itemModel);
+	models.append(model);
+	connect(itemModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(myInvalidate()));
+}
+
+void MultiFilterSortModel::removeFilterModel(MultiFilterInterface *model)
+{
+	QAbstractItemModel *itemModel = dynamic_cast<QAbstractItemModel *>(model);
+	Q_ASSERT(itemModel);
+	models.removeAll(model);
+	disconnect(itemModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(myInvalidate()));
+}
+
+void MultiFilterSortModel::clearFilter()
+{
+	justCleared = true;
+	Q_FOREACH(MultiFilterInterface *iface, models){
+		iface->clearFilter();
+	}
+	justCleared = false;
+	myInvalidate();
+}
+
+void BuddyFilterModel::clearFilter()
+{
+	memset(checkState, false, rowCount());
+	checkState[rowCount() - 1] = false;
+	anyChecked = false;
+	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
+}
+
+void LocationFilterModel::clearFilter()
+{
+	memset(checkState, false, rowCount());
+	checkState[rowCount() - 1] = false;
+	anyChecked = false;
+	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
+}
+
+void TagFilterModel::clearFilter()
+{
+	memset(checkState, false, rowCount());
+	checkState[rowCount() - 1] = false;
+	anyChecked = false;
+	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
+}
\ No newline at end of file
diff --git a/qt-ui/filtermodels.h b/qt-ui/filtermodels.h
new file mode 100644
index 0000000..353e9d0
--- /dev/null
+++ b/qt-ui/filtermodels.h
@@ -0,0 +1,87 @@
+#ifndef FILTERMODELS_H
+#define FILTERMODELS_H
+
+#include <QStringListModel>
+#include <QSortFilterProxyModel>
+
+class MultiFilterInterface {
+public:
+	MultiFilterInterface() : checkState(NULL){};
+	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const = 0;
+	virtual bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const = 0;
+	virtual void clearFilter() = 0;
+	bool *checkState;
+	bool anyChecked;
+};
+
+class TagFilterModel : public QStringListModel, public MultiFilterInterface{
+	Q_OBJECT
+public:
+	static TagFilterModel *instance();
+	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const;
+	bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const;
+	void clearFilter();
+public
+slots:
+	void repopulate();
+
+private:
+	explicit TagFilterModel(QObject *parent = 0);
+};
+
+class BuddyFilterModel : public QStringListModel, public MultiFilterInterface{
+	Q_OBJECT
+public:
+	static BuddyFilterModel *instance();
+	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const;
+	bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const;
+	void clearFilter();
+public
+slots:
+	void repopulate();
+
+private:
+	explicit BuddyFilterModel(QObject *parent = 0);
+};
+
+class LocationFilterModel : public QStringListModel, public MultiFilterInterface{
+	Q_OBJECT
+public:
+	static LocationFilterModel *instance();
+	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const;
+	bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const;
+	void clearFilter();
+public
+slots:
+	void repopulate();
+
+private:
+	explicit LocationFilterModel(QObject *parent = 0);
+};
+
+class MultiFilterSortModel : public QSortFilterProxyModel {
+	Q_OBJECT
+public:
+	static MultiFilterSortModel *instance();
+	virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
+	void addFilterModel(MultiFilterInterface *model);
+	void removeFilterModel(MultiFilterInterface *model);
+public slots:
+	void myInvalidate();
+	void clearFilter();
+private:
+	MultiFilterSortModel(QObject *parent = 0);
+	QList<MultiFilterInterface*> models;
+	bool justCleared;
+};
+
+#endif
\ No newline at end of file
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 858407a..9341916 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -44,6 +44,7 @@
 #include "planner.h"
 #include "configuredivecomputerdialog.h"
 #include "statistics/statisticswidget.h"
+#include "filtermodels.h"
 #ifndef NO_PRINTING
 #include <QPrintDialog>
 #include "printdialog.h"
diff --git a/qt-ui/models.cpp b/qt-ui/models.cpp
index a8e5612..8bf6627 100644
--- a/qt-ui/models.cpp
+++ b/qt-ui/models.cpp
@@ -2252,471 +2252,6 @@ int LanguageModel::rowCount(const QModelIndex &parent) const
 	return languages.count();
 }
 
-
-TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
-{
-}
-
-TagFilterModel *TagFilterModel::instance()
-{
-	static TagFilterModel *self = new TagFilterModel();
-	return self;
-}
-
-QVariant TagFilterModel::data(const QModelIndex &index, int role) const
-{
-	if (role == Qt::CheckStateRole) {
-		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
-	} else if (role == Qt::DisplayRole) {
-		QString tag = stringList()[index.row()];
-		int count = count_dives_with_tag(tag.toUtf8().data());
-		return tag + QString(" (%1)").arg(count);
-	}
-	return QVariant();
-}
-
-Qt::ItemFlags TagFilterModel::flags(const QModelIndex &index) const
-{
-	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
-}
-
-void TagFilterModel::repopulate()
-{
-	if (g_tag_list == NULL)
-		return;
-	QStringList list;
-	struct tag_entry *current_tag_entry = g_tag_list->next;
-	while (current_tag_entry != NULL) {
-		list.append(QString(current_tag_entry->tag->name));
-		current_tag_entry = current_tag_entry->next;
-	}
-	qSort(list);
-	list << tr("Empty Tags");
-	setStringList(list);
-	delete[] checkState;
-	checkState = new bool[list.count()];
-	memset(checkState, false, list.count());
-	checkState[list.count() - 1] = false;
-	anyChecked = false;
-}
-
-bool TagFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
-	if (role == Qt::CheckStateRole) {
-		checkState[index.row()] = value.toBool();
-		anyChecked = false;
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] == true) {
-				anyChecked = true;
-				break;
-			}
-		}
-		dataChanged(index, index);
-		return true;
-	}
-	return false;
-}
-
-bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
-{
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-	if (!d) { // It's a trip, only show the ones that have dives to be shown.
-		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
-			if (filterRow(i, index0, sourceModel))
-				return true;
-		}
-		return false;
-	}
-	// 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;
-	}
-
-	// have at least one tag.
-	QStringList tagList = stringList();
-	if (!tagList.isEmpty()) {
-		tagList.removeLast(); // remove the "Show Empty Tags";
-		while (head) {
-			QString tagName(head->tag->name);
-			int index = tagList.indexOf(tagName);
-			if (checkState[index])
-				return true;
-			head = head->next;
-		}
-	}
-	return false;
-}
-
-bool TagFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
-{
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-
-	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
-	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
-	struct dive *d = (struct dive *)diveVariant.value<void *>();
-
-	bool show = doFilter(d, index0, sourceModel);
-	filter_dive(d, show);
-	return show;
-}
-
-BuddyFilterModel::BuddyFilterModel(QObject *parent) : QStringListModel(parent)
-{
-}
-
-BuddyFilterModel *BuddyFilterModel::instance()
-{
-	static BuddyFilterModel *self = new BuddyFilterModel();
-	return self;
-}
-
-bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
-{
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-	if (!d) { // It's a trip, only show the ones that have dives to be shown.
-		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
-			if (filterRow(i, index0, sourceModel))
-				return true;
-		}
-		return false;
-	}
-
-	// Checked means 'Show', Unchecked means 'Hide'.
-	QString diveBuddy(d->buddy);
-	QString divemaster(d->divemaster);
-	// only show empty buddie dives if the user checked that.
-	if (diveBuddy.isEmpty() && divemaster.isEmpty()) {
-		if (rowCount() > 0)
-			return checkState[rowCount() - 1];
-		else
-			return true;
-	}
-
-	// have at least one buddy
-	QStringList buddyList = stringList();
-	if (!buddyList.isEmpty()) {
-		buddyList.removeLast(); // remove the "Show Empty Tags";
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] && (diveBuddy.indexOf(stringList()[i]) != -1 || divemaster.indexOf(stringList()[i]) != -1)) {
-				return true;
-			}
-		}
-	}
-	return false;
-}
-
-bool BuddyFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
-{
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-
-	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
-	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
-	struct dive *d = (struct dive *)diveVariant.value<void *>();
-
-	return doFilter(d, index0, sourceModel);
-}
-
-Qt::ItemFlags BuddyFilterModel::flags(const QModelIndex &index) const
-{
-	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
-}
-
-void BuddyFilterModel::repopulate()
-{
-	QStringList list;
-	struct dive *dive;
-	int i = 0;
-	for_each_dive (i, dive) {
-		QString persons = QString(dive->buddy) + "," + QString(dive->divemaster);
-		Q_FOREACH(const QString& person, persons.split(',', QString::SkipEmptyParts)){
-			// Remove any leading spaces
-			if (!list.contains(person.trimmed())) {
-				list.append(person.trimmed());
-			}
-		}
-	}
-	qSort(list);
-	list << tr("No buddies");
-	setStringList(list);
-	delete[] checkState;
-	checkState = new bool[list.count()];
-	memset(checkState, false, list.count());
-	checkState[list.count() - 1] = false;
-	anyChecked = false;
-}
-
-QVariant BuddyFilterModel::data(const QModelIndex &index, int role) const
-{
-	if (role == Qt::CheckStateRole) {
-		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
-	} else if (role == Qt::DisplayRole) {
-		QString person = stringList()[index.row()];
-		int count = count_dives_with_person(person.toUtf8().data());
-		return person + QString(" (%1)").arg(count);
-	}
-	return QVariant();
-}
-
-
-bool BuddyFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
-	if (role == Qt::CheckStateRole) {
-		checkState[index.row()] = value.toBool();
-		anyChecked = false;
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] == true) {
-				anyChecked = true;
-				break;
-			}
-		}
-		dataChanged(index, index);
-		return true;
-	}
-	return false;
-}
-
-LocationFilterModel::LocationFilterModel(QObject *parent) : QStringListModel(parent)
-{
-}
-
-QVariant LocationFilterModel::data(const QModelIndex &index, int role) const
-{
-	if (role == Qt::CheckStateRole) {
-		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
-	} else if (role == Qt::DisplayRole) {
-		QString location = stringList()[index.row()];
-		int count = count_dives_with_location(location.toUtf8().data());
-		return location + QString(" (%1)").arg(count);
-	}
-	return QVariant();
-}
-
-bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
-{
-	if (!anyChecked) {
-		return true;
-	}
-
-	if (!d) { // It's a trip, only show the ones that have dives to be shown.
-		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
-			if (filterRow(i, index0, sourceModel))
-				return true;
-		}
-		return false;
-	}
-
-	// Checked means 'Show', Unchecked means 'Hide'.
-	QString location(d->location);
-	// only show empty location dives if the user checked that.
-	if (location.isEmpty()) {
-		if (rowCount() > 0)
-			return checkState[rowCount() - 1];
-		else
-			return true;
-	}
-
-	// there is a location selected
-	QStringList locationList = stringList();
-	if (!locationList.isEmpty()) {
-		locationList.removeLast(); // remove the "Show Empty Tags";
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] && (location.indexOf(stringList()[i]) != -1)) {
-				return true;
-			}
-		}
-	}
-	return false;
-}
-
-bool LocationFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
-{
-
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-
-	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
-	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
-	struct dive *d = (struct dive *)diveVariant.value<void *>();
-
-	return doFilter(d, index0, sourceModel);
-}
-
-Qt::ItemFlags LocationFilterModel::flags(const QModelIndex &index) const
-{
-	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
-}
-
-LocationFilterModel *LocationFilterModel::instance()
-{
-	static LocationFilterModel *self = new LocationFilterModel();
-	return self;
-}
-
-void LocationFilterModel::repopulate()
-{
-	QStringList list;
-	struct dive *dive;
-	int i = 0;
-	for_each_dive (i, dive) {
-		QString location(dive->location);
-		if (!location.isEmpty() && !list.contains(location)) {
-			list.append(location);
-		}
-	}
-	qSort(list);
-	list << tr("No location set");
-	setStringList(list);
-	delete[] checkState;
-	checkState = new bool[list.count()];
-	memset(checkState, false, list.count());
-	checkState[list.count() - 1] = false;
-	anyChecked = false;
-}
-
-bool LocationFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
-	if (role == Qt::CheckStateRole) {
-		checkState[index.row()] = value.toBool();
-		anyChecked = false;
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] == true) {
-				anyChecked = true;
-				break;
-			}
-		}
-		dataChanged(index, index);
-		return true;
-	}
-	return false;
-}
-
-MultiFilterSortModel *MultiFilterSortModel::instance()
-{
-	static MultiFilterSortModel *self = new MultiFilterSortModel();
-	return self;
-}
-
-MultiFilterSortModel::MultiFilterSortModel(QObject *parent) : QSortFilterProxyModel(parent), justCleared(false)
-{
-}
-
-bool MultiFilterSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
-{
-	if (justCleared || models.isEmpty())
-		return true;
-
-	bool shouldShow = true;
-	QModelIndex index0 = sourceModel()->index(source_row, 0, source_parent);
-	QVariant diveVariant = sourceModel()->data(index0, DiveTripModel::DIVE_ROLE);
-	struct dive *d = (struct dive *)diveVariant.value<void *>();
-
-	Q_FOREACH (MultiFilterInterface *model, models) {
-		if (!model->doFilter(d, index0, sourceModel()))
-			shouldShow = false;
-	}
-	// if it's a dive, mark it accordingly
-	filter_dive(d, shouldShow);
-	return shouldShow;
-}
-
-void MultiFilterSortModel::myInvalidate()
-{
-	int i;
-	struct dive *d;
-	DiveListView *dlv = MainWindow::instance()->dive_list();
-
-	invalidate();
-	// first make sure the trips are no longer shown as selected
-	// (but without updating the selection state of the dives... this just cleans
-	//  up an oddity in the filter handling)
-	dlv->clearTripSelection();
-
-	// if we have no more selected dives, clean up the display - this later triggers us
-	// to pick one of the dives that are shown in the list as selected dive which is the
-	// natural behavior
-	if (amount_selected == 0) {
-		MainWindow::instance()->cleanUpEmpty();
-	} else {
-		// otherwise find the dives that should still be selected (the filter above unselected any
-		// dive that's no longer visible) and select them again
-		QList<int>curSelectedDives;
-		for_each_dive (i, d) {
-			if(d->selected)
-				curSelectedDives.append(get_divenr(d));
-		}
-		dlv->selectDives(curSelectedDives);
-	}
-}
-
-void MultiFilterSortModel::addFilterModel(MultiFilterInterface *model)
-{
-	QAbstractItemModel *itemModel = dynamic_cast<QAbstractItemModel *>(model);
-	Q_ASSERT(itemModel);
-	models.append(model);
-	connect(itemModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(myInvalidate()));
-}
-
-void MultiFilterSortModel::removeFilterModel(MultiFilterInterface *model)
-{
-	QAbstractItemModel *itemModel = dynamic_cast<QAbstractItemModel *>(model);
-	Q_ASSERT(itemModel);
-	models.removeAll(model);
-	disconnect(itemModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(myInvalidate()));
-}
-
-void MultiFilterSortModel::clearFilter()
-{
-	justCleared = true;
-	Q_FOREACH(MultiFilterInterface *iface, models){
-		iface->clearFilter();
-	}
-	justCleared = false;
-	myInvalidate();
-}
-
-void BuddyFilterModel::clearFilter()
-{
-	memset(checkState, false, rowCount());
-	checkState[rowCount() - 1] = false;
-	anyChecked = false;
-	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
-}
-
-void LocationFilterModel::clearFilter()
-{
-	memset(checkState, false, rowCount());
-	checkState[rowCount() - 1] = false;
-	anyChecked = false;
-	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
-}
-
-void TagFilterModel::clearFilter()
-{
-	memset(checkState, false, rowCount());
-	checkState[rowCount() - 1] = false;
-	anyChecked = false;
-	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
-}
-
 ExtraDataModel::ExtraDataModel(QObject *parent) : CleanerTableModel(parent),
 	rows(0)
 {
diff --git a/qt-ui/models.h b/qt-ui/models.h
index 8a2d3dc..ad0d7b7 100644
--- a/qt-ui/models.h
+++ b/qt-ui/models.h
@@ -438,84 +438,4 @@ private:
 	QStringList languages;
 };
 
-class MultiFilterInterface {
-public:
-	MultiFilterInterface() : checkState(NULL){};
-	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const = 0;
-	virtual bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const = 0;
-	virtual void clearFilter() = 0;
-	bool *checkState;
-	bool anyChecked;
-};
-
-class TagFilterModel : public QStringListModel, public MultiFilterInterface{
-	Q_OBJECT
-public:
-	static TagFilterModel *instance();
-	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
-	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
-	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const;
-	bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const;
-	void clearFilter();
-public
-slots:
-	void repopulate();
-
-private:
-	explicit TagFilterModel(QObject *parent = 0);
-};
-
-class BuddyFilterModel : public QStringListModel, public MultiFilterInterface{
-	Q_OBJECT
-public:
-	static BuddyFilterModel *instance();
-	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
-	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
-	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const;
-	bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const;
-	void clearFilter();
-public
-slots:
-	void repopulate();
-
-private:
-	explicit BuddyFilterModel(QObject *parent = 0);
-};
-
-class LocationFilterModel : public QStringListModel, public MultiFilterInterface{
-	Q_OBJECT
-public:
-	static LocationFilterModel *instance();
-	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
-	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
-	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const;
-	bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const;
-	void clearFilter();
-public
-slots:
-	void repopulate();
-
-private:
-	explicit LocationFilterModel(QObject *parent = 0);
-};
-
-
-class MultiFilterSortModel : public QSortFilterProxyModel {
-	Q_OBJECT
-public:
-	static MultiFilterSortModel *instance();
-	virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
-	void addFilterModel(MultiFilterInterface *model);
-	void removeFilterModel(MultiFilterInterface *model);
-public slots:
-	void myInvalidate();
-	void clearFilter();
-private:
-	MultiFilterSortModel(QObject *parent = 0);
-	QList<MultiFilterInterface*> models;
-	bool justCleared;
-};
 #endif // MODELS_H
diff --git a/qt-ui/simplewidgets.cpp b/qt-ui/simplewidgets.cpp
index 850bdcf..fb9b904 100644
--- a/qt-ui/simplewidgets.cpp
+++ b/qt-ui/simplewidgets.cpp
@@ -1,4 +1,5 @@
 #include "simplewidgets.h"
+#include "filtermodels.h"
 
 #include <QLabel>
 #include <QProcess>
diff --git a/subsurface.pro b/subsurface.pro
index 07e7b29..94245fc 100644
--- a/subsurface.pro
+++ b/subsurface.pro
@@ -102,7 +102,8 @@ HEADERS = \
 	qt-ui/statistics/statisticswidget.h \
 	qt-ui/statistics/statisticsbar.h \
 	qt-ui/statistics/yearstatistics.h \
-	qt-ui/diveshareexportdialog.h
+	qt-ui/diveshareexportdialog.h \
+	qt-ui/filtermodels.h
 
 android: HEADERS -= \
 	qt-ui/usermanual.h \
@@ -195,7 +196,8 @@ SOURCES =  \
 	qt-ui/statistics/yearstatistics.cpp \
 	qt-ui/statistics/statisticsbar.cpp \
 	qt-ui/statistics/monthstatistics.cpp \
-	qt-ui/diveshareexportdialog.cpp
+	qt-ui/diveshareexportdialog.cpp \
+	qt-ui/filtermodels.cpp
 
 android: SOURCES += android.cpp
 else: win32: SOURCES += windows.c
-- 
2.1.3

From 5fd2761b5b091cd39d2a552f266c2f2215f5be7b Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 16:34:55 -0200
Subject: [PATCH 02/16] Create a CREATE_INSTANCE_METHOD macro

This is just to simplify the creation of more filters.
more macros will be used, because I tend to abuse them.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 29 ++++++++++++-----------------
 1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 3dabc80..a60b2c0 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -4,14 +4,21 @@
 #include "mainwindow.h"
 #include "display.h"
 
-TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
-{
+#define CREATE_INSTANCE_METHOD( CLASS ) \
+CLASS *CLASS::instance() \
+{ \
+	static CLASS *self = new CLASS(); \
+	return self; \
 }
 
-TagFilterModel *TagFilterModel::instance()
+CREATE_INSTANCE_METHOD(TagFilterModel);
+CREATE_INSTANCE_METHOD(BuddyFilterModel);
+CREATE_INSTANCE_METHOD(LocationFilterModel);
+
+#undef CREATE_INSTANCE_METHOD
+
+TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
 {
-	static TagFilterModel *self = new TagFilterModel();
-	return self;
 }
 
 QVariant TagFilterModel::data(const QModelIndex &index, int role) const
@@ -126,12 +133,6 @@ BuddyFilterModel::BuddyFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
 
-BuddyFilterModel *BuddyFilterModel::instance()
-{
-	static BuddyFilterModel *self = new BuddyFilterModel();
-	return self;
-}
-
 bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
 	// If there's nothing checked, this should show everything
@@ -316,12 +317,6 @@ Qt::ItemFlags LocationFilterModel::flags(const QModelIndex &index) const
 	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
 }
 
-LocationFilterModel *LocationFilterModel::instance()
-{
-	static LocationFilterModel *self = new LocationFilterModel();
-	return self;
-}
-
 void LocationFilterModel::repopulate()
 {
 	QStringList list;
-- 
2.1.3

From ed717e891c2b7fbf7f10fca716a1b8a39eae55d4 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 16:41:37 -0200
Subject: [PATCH 03/16] More cleanup using Macros.

The setData of any filter based on a StringList with
checkboxes should be the same, so let's use the same
codebase for it.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 81 ++++++++++++++------------------------------------
 1 file changed, 23 insertions(+), 58 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index a60b2c0..eaf15f4 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -14,9 +14,32 @@ CLASS *CLASS::instance() \
 CREATE_INSTANCE_METHOD(TagFilterModel);
 CREATE_INSTANCE_METHOD(BuddyFilterModel);
 CREATE_INSTANCE_METHOD(LocationFilterModel);
+CREATE_INSTANCE_METHOD(MultiFilterSortModel);
 
 #undef CREATE_INSTANCE_METHOD
 
+#define CREATE_MODEL_SET_DATA_METHOD( CLASS ) \
+bool CLASS::setData(const QModelIndex &index, const QVariant &value, int role) \
+{ \
+	if (role == Qt::CheckStateRole) { \
+		checkState[index.row()] = value.toBool(); \
+		anyChecked = false; \
+		for (int i = 0; i < rowCount(); i++) { \
+			if (checkState[i] == true) { \
+				anyChecked = true; \
+				break; \
+			} \
+		} \
+		dataChanged(index, index); \
+		return true; \
+	} \
+	return false; \
+}
+
+CREATE_MODEL_SET_DATA_METHOD(TagFilterModel);
+CREATE_MODEL_SET_DATA_METHOD(BuddyFilterModel);
+CREATE_MODEL_SET_DATA_METHOD(LocationFilterModel);
+
 TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
@@ -58,23 +81,6 @@ void TagFilterModel::repopulate()
 	anyChecked = false;
 }
 
-bool TagFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
-	if (role == Qt::CheckStateRole) {
-		checkState[index.row()] = value.toBool();
-		anyChecked = false;
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] == true) {
-				anyChecked = true;
-				break;
-			}
-		}
-		dataChanged(index, index);
-		return true;
-	}
-	return false;
-}
-
 bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
 	// If there's nothing checked, this should show everything
@@ -226,24 +232,6 @@ QVariant BuddyFilterModel::data(const QModelIndex &index, int role) const
 	return QVariant();
 }
 
-
-bool BuddyFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
-	if (role == Qt::CheckStateRole) {
-		checkState[index.row()] = value.toBool();
-		anyChecked = false;
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] == true) {
-				anyChecked = true;
-				break;
-			}
-		}
-		dataChanged(index, index);
-		return true;
-	}
-	return false;
-}
-
 LocationFilterModel::LocationFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
@@ -338,29 +326,6 @@ void LocationFilterModel::repopulate()
 	anyChecked = false;
 }
 
-bool LocationFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
-	if (role == Qt::CheckStateRole) {
-		checkState[index.row()] = value.toBool();
-		anyChecked = false;
-		for (int i = 0; i < rowCount(); i++) {
-			if (checkState[i] == true) {
-				anyChecked = true;
-				break;
-			}
-		}
-		dataChanged(index, index);
-		return true;
-	}
-	return false;
-}
-
-MultiFilterSortModel *MultiFilterSortModel::instance()
-{
-	static MultiFilterSortModel *self = new MultiFilterSortModel();
-	return self;
-}
-
 MultiFilterSortModel::MultiFilterSortModel(QObject *parent) : QSortFilterProxyModel(parent), justCleared(false)
 {
 }
-- 
2.1.3

From 359171020adf8fdf35e22de65f599eff13fd0402 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 16:44:32 -0200
Subject: [PATCH 04/16] Clear filter is always the same for a filter based on
 stringlist

So, let's always use the same codebasee

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 41 +++++++++++++++++------------------------
 1 file changed, 17 insertions(+), 24 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index eaf15f4..8c67ca2 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -40,6 +40,23 @@ CREATE_MODEL_SET_DATA_METHOD(TagFilterModel);
 CREATE_MODEL_SET_DATA_METHOD(BuddyFilterModel);
 CREATE_MODEL_SET_DATA_METHOD(LocationFilterModel);
 
+#undef CREATE_MODEL_SET_DATA_METHOD
+
+#define CREATE_CLEAR_FILTER_METHOD( CLASS ) \
+void CLASS::clearFilter() \
+{ \
+	memset(checkState, false, rowCount()); \
+	checkState[rowCount() - 1] = false; \
+	anyChecked = false; \
+	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0)); \
+}
+
+CREATE_CLEAR_FILTER_METHOD(TagFilterModel);
+CREATE_CLEAR_FILTER_METHOD(BuddyFilterModel);
+CREATE_CLEAR_FILTER_METHOD(LocationFilterModel);
+
+#undef CREATE_CLEAR_FILTER_METHOD
+
 TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
@@ -404,27 +421,3 @@ void MultiFilterSortModel::clearFilter()
 	justCleared = false;
 	myInvalidate();
 }
-
-void BuddyFilterModel::clearFilter()
-{
-	memset(checkState, false, rowCount());
-	checkState[rowCount() - 1] = false;
-	anyChecked = false;
-	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
-}
-
-void LocationFilterModel::clearFilter()
-{
-	memset(checkState, false, rowCount());
-	checkState[rowCount() - 1] = false;
-	anyChecked = false;
-	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
-}
-
-void TagFilterModel::clearFilter()
-{
-	memset(checkState, false, rowCount());
-	checkState[rowCount() - 1] = false;
-	anyChecked = false;
-	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0));
-}
\ No newline at end of file
-- 
2.1.3

From fc280737b9b013342f0af7c04dc2e78693d46f25 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 16:48:13 -0200
Subject: [PATCH 05/16] Create a common macro for flags

samething as the other commits, use common code.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 25 ++++++++++---------------
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 8c67ca2..557460b 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -57,6 +57,16 @@ CREATE_CLEAR_FILTER_METHOD(LocationFilterModel);
 
 #undef CREATE_CLEAR_FILTER_METHOD
 
+#define CREATE_FLAGS_METHOD( CLASS ) \
+Qt::ItemFlags CLASS::flags(const QModelIndex &index) const \
+{ \
+	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable; \
+}
+
+CREATE_FLAGS_METHOD(TagFilterModel);
+CREATE_FLAGS_METHOD(BuddyFilterModel);
+CREATE_FLAGS_METHOD(LocationFilterModel);
+
 TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
@@ -73,11 +83,6 @@ QVariant TagFilterModel::data(const QModelIndex &index, int role) const
 	return QVariant();
 }
 
-Qt::ItemFlags TagFilterModel::flags(const QModelIndex &index) const
-{
-	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
-}
-
 void TagFilterModel::repopulate()
 {
 	if (g_tag_list == NULL)
@@ -208,11 +213,6 @@ bool BuddyFilterModel::filterRow(int source_row, const QModelIndex &source_paren
 	return doFilter(d, index0, sourceModel);
 }
 
-Qt::ItemFlags BuddyFilterModel::flags(const QModelIndex &index) const
-{
-	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
-}
-
 void BuddyFilterModel::repopulate()
 {
 	QStringList list;
@@ -317,11 +317,6 @@ bool LocationFilterModel::filterRow(int source_row, const QModelIndex &source_pa
 	return doFilter(d, index0, sourceModel);
 }
 
-Qt::ItemFlags LocationFilterModel::flags(const QModelIndex &index) const
-{
-	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable;
-}
-
 void LocationFilterModel::repopulate()
 {
 	QStringList list;
-- 
2.1.3

From 0ee68b70f89202cef9256b25d95f3166be49a6db Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 16:51:48 -0200
Subject: [PATCH 06/16] Call all common methods once per class in an easy way.

New method to simplify the creation of 4 of the common
methods for each filter in an easy way. There are
a few other methods that I'm also thinking on how
to do this.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 32 ++++++++++----------------------
 1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 557460b..71fa8f8 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -11,13 +11,6 @@ CLASS *CLASS::instance() \
 	return self; \
 }
 
-CREATE_INSTANCE_METHOD(TagFilterModel);
-CREATE_INSTANCE_METHOD(BuddyFilterModel);
-CREATE_INSTANCE_METHOD(LocationFilterModel);
-CREATE_INSTANCE_METHOD(MultiFilterSortModel);
-
-#undef CREATE_INSTANCE_METHOD
-
 #define CREATE_MODEL_SET_DATA_METHOD( CLASS ) \
 bool CLASS::setData(const QModelIndex &index, const QVariant &value, int role) \
 { \
@@ -36,12 +29,6 @@ bool CLASS::setData(const QModelIndex &index, const QVariant &value, int role) \
 	return false; \
 }
 
-CREATE_MODEL_SET_DATA_METHOD(TagFilterModel);
-CREATE_MODEL_SET_DATA_METHOD(BuddyFilterModel);
-CREATE_MODEL_SET_DATA_METHOD(LocationFilterModel);
-
-#undef CREATE_MODEL_SET_DATA_METHOD
-
 #define CREATE_CLEAR_FILTER_METHOD( CLASS ) \
 void CLASS::clearFilter() \
 { \
@@ -51,21 +38,22 @@ void CLASS::clearFilter() \
 	emit dataChanged(createIndex(0,0), createIndex(rowCount()-1, 0)); \
 }
 
-CREATE_CLEAR_FILTER_METHOD(TagFilterModel);
-CREATE_CLEAR_FILTER_METHOD(BuddyFilterModel);
-CREATE_CLEAR_FILTER_METHOD(LocationFilterModel);
-
-#undef CREATE_CLEAR_FILTER_METHOD
-
 #define CREATE_FLAGS_METHOD( CLASS ) \
 Qt::ItemFlags CLASS::flags(const QModelIndex &index) const \
 { \
 	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable; \
 }
 
-CREATE_FLAGS_METHOD(TagFilterModel);
-CREATE_FLAGS_METHOD(BuddyFilterModel);
-CREATE_FLAGS_METHOD(LocationFilterModel);
+#define CREATE_COMMON_METHODS_FOR_FILTER( CLASS ) \
+CREATE_FLAGS_METHOD( CLASS ); \
+CREATE_CLEAR_FILTER_METHOD( CLASS ); \
+CREATE_MODEL_SET_DATA_METHOD( CLASS ); \
+CREATE_INSTANCE_METHOD( CLASS )
+
+CREATE_COMMON_METHODS_FOR_FILTER(TagFilterModel);
+CREATE_COMMON_METHODS_FOR_FILTER(BuddyFilterModel);
+CREATE_COMMON_METHODS_FOR_FILTER(LocationFilterModel);
+CREATE_INSTANCE_METHOD(MultiFilterSortModel);
 
 TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
 {
-- 
2.1.3

From 93203e07473239fd3432f9cf1c6d564c6bd4c32f Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 16:59:00 -0200
Subject: [PATCH 07/16] Last one: Common  'data' method for StringList based
 Filters.

This is the last of the series of Macros that I'll do to ease
the creation of a QStringListModel based filter.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 60 ++++++++++++++++----------------------------------
 1 file changed, 19 insertions(+), 41 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 71fa8f8..35f9b41 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -44,33 +44,35 @@ Qt::ItemFlags CLASS::flags(const QModelIndex &index) const \
 	return QStringListModel::flags(index) | Qt::ItemIsUserCheckable; \
 }
 
-#define CREATE_COMMON_METHODS_FOR_FILTER( CLASS ) \
+#define CREATE_DATA_METHOD( CLASS, COUNTER_FUNCTION ) \
+QVariant CLASS::data(const QModelIndex &index, int role) const \
+{ \
+	if (role == Qt::CheckStateRole) { \
+		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked; \
+	} else if (role == Qt::DisplayRole) { \
+		QString value = stringList()[index.row()]; \
+		int count = COUNTER_FUNCTION(value.toUtf8().data()); \
+		return value + QString(" (%1)").arg(count); \
+	} \
+	return QVariant(); \
+}
+
+#define CREATE_COMMON_METHODS_FOR_FILTER( CLASS, COUNTER_FUNCTION ) \
 CREATE_FLAGS_METHOD( CLASS ); \
 CREATE_CLEAR_FILTER_METHOD( CLASS ); \
 CREATE_MODEL_SET_DATA_METHOD( CLASS ); \
-CREATE_INSTANCE_METHOD( CLASS )
+CREATE_INSTANCE_METHOD( CLASS ); \
+CREATE_DATA_METHOD( CLASS, COUNTER_FUNCTION )
 
-CREATE_COMMON_METHODS_FOR_FILTER(TagFilterModel);
-CREATE_COMMON_METHODS_FOR_FILTER(BuddyFilterModel);
-CREATE_COMMON_METHODS_FOR_FILTER(LocationFilterModel);
+CREATE_COMMON_METHODS_FOR_FILTER(TagFilterModel, count_dives_with_tag);
+CREATE_COMMON_METHODS_FOR_FILTER(BuddyFilterModel, count_dives_with_person);
+CREATE_COMMON_METHODS_FOR_FILTER(LocationFilterModel, count_dives_with_location);
 CREATE_INSTANCE_METHOD(MultiFilterSortModel);
 
 TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
 
-QVariant TagFilterModel::data(const QModelIndex &index, int role) const
-{
-	if (role == Qt::CheckStateRole) {
-		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
-	} else if (role == Qt::DisplayRole) {
-		QString tag = stringList()[index.row()];
-		int count = count_dives_with_tag(tag.toUtf8().data());
-		return tag + QString(" (%1)").arg(count);
-	}
-	return QVariant();
-}
-
 void TagFilterModel::repopulate()
 {
 	if (g_tag_list == NULL)
@@ -225,34 +227,10 @@ void BuddyFilterModel::repopulate()
 	anyChecked = false;
 }
 
-QVariant BuddyFilterModel::data(const QModelIndex &index, int role) const
-{
-	if (role == Qt::CheckStateRole) {
-		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
-	} else if (role == Qt::DisplayRole) {
-		QString person = stringList()[index.row()];
-		int count = count_dives_with_person(person.toUtf8().data());
-		return person + QString(" (%1)").arg(count);
-	}
-	return QVariant();
-}
-
 LocationFilterModel::LocationFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
 
-QVariant LocationFilterModel::data(const QModelIndex &index, int role) const
-{
-	if (role == Qt::CheckStateRole) {
-		return checkState[index.row()] ? Qt::Checked : Qt::Unchecked;
-	} else if (role == Qt::DisplayRole) {
-		QString location = stringList()[index.row()];
-		int count = count_dives_with_location(location.toUtf8().data());
-		return location + QString(" (%1)").arg(count);
-	}
-	return QVariant();
-}
-
 bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
 	if (!anyChecked) {
-- 
2.1.3

From e3c01c2d324fb01ae992df86e2be49b74aef0716 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:07:05 -0200
Subject: [PATCH 08/16] Added skeleton of the Suits Filter.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 20 ++++++++++++++++++++
 qt-ui/filtermodels.h   | 18 ++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 35f9b41..da12379 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -67,8 +67,28 @@ CREATE_DATA_METHOD( CLASS, COUNTER_FUNCTION )
 CREATE_COMMON_METHODS_FOR_FILTER(TagFilterModel, count_dives_with_tag);
 CREATE_COMMON_METHODS_FOR_FILTER(BuddyFilterModel, count_dives_with_person);
 CREATE_COMMON_METHODS_FOR_FILTER(LocationFilterModel, count_dives_with_location);
+CREATE_COMMON_METHODS_FOR_FILTER(SuitsFilterModel, count_dives_with_location);
+
 CREATE_INSTANCE_METHOD(MultiFilterSortModel);
 
+SuitsFilterModel::SuitsFilterModel(QObject *parent): QStringListModel(parent)
+{
+}
+
+bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
+{
+	return false;
+}
+
+bool SuitsFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
+{
+	return false;
+}
+
+void SuitsFilterModel::repopulate()
+{
+}
+
 TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
 {
 }
diff --git a/qt-ui/filtermodels.h b/qt-ui/filtermodels.h
index 353e9d0..3d64356 100644
--- a/qt-ui/filtermodels.h
+++ b/qt-ui/filtermodels.h
@@ -68,6 +68,24 @@ private:
 	explicit LocationFilterModel(QObject *parent = 0);
 };
 
+class SuitsFilterModel : public QStringListModel, public MultiFilterInterface{
+	Q_OBJECT
+public:
+	static SuitsFilterModel *instance();
+	virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+	virtual bool filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const;
+	bool doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const;
+	void clearFilter();
+public
+slots:
+	void repopulate();
+
+private:
+	explicit SuitsFilterModel(QObject *parent = 0);
+};
+
 class MultiFilterSortModel : public QSortFilterProxyModel {
 	Q_OBJECT
 public:
-- 
2.1.3

From fffc48872573b6d315d13b0865c9912542b5fd45 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:09:54 -0200
Subject: [PATCH 09/16] Suits update method done.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index da12379..6c80ca5 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -87,6 +87,23 @@ bool SuitsFilterModel::filterRow(int source_row, const QModelIndex &source_paren
 
 void SuitsFilterModel::repopulate()
 {
+	QStringList list;
+	struct dive *dive;
+	int i = 0;
+	for_each_dive (i, dive) {
+		QString suit(dive->suit);
+		if (!suit.isEmpty() && !list.contains(suit)) {
+			list.append(suit);
+		}
+	}
+	qSort(list);
+	list << tr("No suit set");
+	setStringList(list);
+	delete[] checkState;
+	checkState = new bool[list.count()];
+	memset(checkState, false, list.count());
+	checkState[list.count() - 1] = false;
+	anyChecked = false;
 }
 
 TagFilterModel::TagFilterModel(QObject *parent) : QStringListModel(parent)
-- 
2.1.3

From bf592347b2a0f82583b015e897dc356a92badf6b Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:10:33 -0200
Subject: [PATCH 10/16] Suits filterRoe method done.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 6c80ca5..4ed2948 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -82,7 +82,16 @@ bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel
 
 bool SuitsFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
 {
-	return false;
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
+
+	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
+	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
+	struct dive *d = (struct dive *)diveVariant.value<void *>();
+
+	return doFilter(d, index0, sourceModel);
 }
 
 void SuitsFilterModel::repopulate()
-- 
2.1.3

From e55a07880228ff4ee4bbf7ed519ff726ede74f59 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:12:46 -0200
Subject: [PATCH 11/16] Create the doFilter for the Suits.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 4ed2948..9e3c763 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -77,6 +77,38 @@ SuitsFilterModel::SuitsFilterModel(QObject *parent): QStringListModel(parent)
 
 bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
+	if (!anyChecked) {
+		return true;
+	}
+
+	if (!d) { // It's a trip, only show the ones that have dives to be shown.
+		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
+			if (filterRow(i, index0, sourceModel))
+				return true;
+		}
+		return false;
+	}
+
+	// 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;
+	}
+
+	// there is a suit selected
+	QStringList suitList = stringList();
+	if (!suitList.isEmpty()) {
+		suitList.removeLast(); // remove the "Show Empty Suits";
+		for (int i = 0; i < rowCount(); i++) {
+			if (checkState[i] && (suit.indexOf(stringList()[i]) != -1)) {
+				return true;
+			}
+		}
+	}
 	return false;
 }
 
-- 
2.1.3

From c5756eaaafd0fda8e996b8f3717c9b3b58018494 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:13:39 -0200
Subject: [PATCH 12/16] This if is already checked before.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 9e3c763..2c5ace3 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -77,10 +77,6 @@ SuitsFilterModel::SuitsFilterModel(QObject *parent): QStringListModel(parent)
 
 bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
-	if (!anyChecked) {
-		return true;
-	}
-
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
@@ -173,10 +169,6 @@ void TagFilterModel::repopulate()
 
 bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
@@ -231,10 +223,6 @@ BuddyFilterModel::BuddyFilterModel(QObject *parent) : QStringListModel(parent)
 
 bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
@@ -311,10 +299,6 @@ LocationFilterModel::LocationFilterModel(QObject *parent) : QStringListModel(par
 
 bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
-	if (!anyChecked) {
-		return true;
-	}
-
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
-- 
2.1.3

From 7ec76627fd7ed8d52b37e236b41496834d06386d Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:29:23 -0200
Subject: [PATCH 13/16] Uups. I removed the wrong if's before.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/filtermodels.cpp | 37 ++++++++++++++++---------------------
 1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/qt-ui/filtermodels.cpp b/qt-ui/filtermodels.cpp
index 2c5ace3..edd62cb 100644
--- a/qt-ui/filtermodels.cpp
+++ b/qt-ui/filtermodels.cpp
@@ -77,6 +77,10 @@ SuitsFilterModel::SuitsFilterModel(QObject *parent): QStringListModel(parent)
 
 bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
+	if (!anyChecked) {
+		return true;
+	}
+
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
@@ -110,11 +114,6 @@ bool SuitsFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel
 
 bool SuitsFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
 {
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-
 	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
 	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
 	struct dive *d = (struct dive *)diveVariant.value<void *>();
@@ -169,6 +168,10 @@ void TagFilterModel::repopulate()
 
 bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
@@ -203,11 +206,6 @@ bool TagFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *
 
 bool TagFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
 {
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-
 	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
 	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
 	struct dive *d = (struct dive *)diveVariant.value<void *>();
@@ -223,6 +221,10 @@ BuddyFilterModel::BuddyFilterModel(QObject *parent) : QStringListModel(parent)
 
 bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
+	// If there's nothing checked, this should show everything
+	if (!anyChecked) {
+		return true;
+	}
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
@@ -257,11 +259,6 @@ bool BuddyFilterModel::doFilter(dive *d, QModelIndex &index0, QAbstractItemModel
 
 bool BuddyFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
 {
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-
 	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
 	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
 	struct dive *d = (struct dive *)diveVariant.value<void *>();
@@ -299,6 +296,10 @@ LocationFilterModel::LocationFilterModel(QObject *parent) : QStringListModel(par
 
 bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstractItemModel *sourceModel) const
 {
+	if (!anyChecked) {
+		return true;
+	}
+
 	if (!d) { // It's a trip, only show the ones that have dives to be shown.
 		for (int i = 0; i < sourceModel->rowCount(index0); i++) {
 			if (filterRow(i, index0, sourceModel))
@@ -332,12 +333,6 @@ bool LocationFilterModel::doFilter(struct dive *d, QModelIndex &index0, QAbstrac
 
 bool LocationFilterModel::filterRow(int source_row, const QModelIndex &source_parent, QAbstractItemModel *sourceModel) const
 {
-
-	// If there's nothing checked, this should show everything
-	if (!anyChecked) {
-		return true;
-	}
-
 	QModelIndex index0 = sourceModel->index(source_row, 0, source_parent);
 	QVariant diveVariant = sourceModel->data(index0, DiveTripModel::DIVE_ROLE);
 	struct dive *d = (struct dive *)diveVariant.value<void *>();
-- 
2.1.3

From 659ed0aa632a6efccdf5b518589ce0d282d96e36 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:32:17 -0200
Subject: [PATCH 14/16] Suits Widget created and working.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qt-ui/mainwindow.cpp    |  1 +
 qt-ui/simplewidgets.cpp | 26 ++++++++++++++++++++++++++
 qt-ui/simplewidgets.h   | 11 +++++++++++
 3 files changed, 38 insertions(+)

diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 9341916..66ebb61 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -185,6 +185,7 @@ void MainWindow::recreateDiveList()
 	TagFilterModel::instance()->repopulate();
 	BuddyFilterModel::instance()->repopulate();
 	LocationFilterModel::instance()->repopulate();
+	SuitsFilterModel::instance()->repopulate();
 }
 
 void MainWindow::current_dive_changed(int divenr)
diff --git a/qt-ui/simplewidgets.cpp b/qt-ui/simplewidgets.cpp
index fb9b904..161f4f1 100644
--- a/qt-ui/simplewidgets.cpp
+++ b/qt-ui/simplewidgets.cpp
@@ -535,6 +535,31 @@ void LocationFilter::hideEvent(QHideEvent *event)
 	QWidget::hideEvent(event);
 }
 
+SuitFilter::SuitFilter(QWidget *parent) : QWidget(parent)
+{
+	ui.setupUi(this);
+	ui.label->setText(tr("Suits: "));
+#if QT_VERSION >= 0x050000
+	ui.filterInternalList->setClearButtonEnabled(true);
+#endif
+	QSortFilterProxyModel *filter = new QSortFilterProxyModel();
+	filter->setSourceModel(SuitsFilterModel::instance());
+	connect(ui.filterInternalList, SIGNAL(textChanged(QString)), filter, SLOT(setFilterFixedString(QString)));
+	ui.filterList->setModel(filter);
+}
+
+void SuitFilter::showEvent(QShowEvent *event)
+{
+	MultiFilterSortModel::instance()->addFilterModel(SuitsFilterModel::instance());
+	QWidget::showEvent(event);
+}
+
+void SuitFilter::hideEvent(QHideEvent *event)
+{
+	MultiFilterSortModel::instance()->removeFilterModel(SuitsFilterModel::instance());
+	QWidget::hideEvent(event);
+}
+
 MultiFilter::MultiFilter(QWidget *parent) : QScrollArea(parent)
 {
 	QWidget *expandedWidget = new QWidget();
@@ -575,6 +600,7 @@ MultiFilter::MultiFilter(QWidget *parent) : QScrollArea(parent)
 	l->addWidget(tagFilter);
 	l->addWidget(new BuddyFilter());
 	l->addWidget(new LocationFilter());
+	l->addWidget(new SuitFilter());
 	l->setContentsMargins(0, 0, 0, 0);
 	l->setSpacing(0);
 
diff --git a/qt-ui/simplewidgets.h b/qt-ui/simplewidgets.h
index 385ce08..25ef654 100644
--- a/qt-ui/simplewidgets.h
+++ b/qt-ui/simplewidgets.h
@@ -161,6 +161,17 @@ private:
 	Ui::FilterWidget ui;
 };
 
+class SuitFilter : public QWidget {
+	Q_OBJECT
+public:
+	SuitFilter(QWidget *parent = 0);
+	virtual void showEvent(QShowEvent *);
+	virtual void hideEvent(QHideEvent *);
+
+private:
+	Ui::FilterWidget ui;
+};
+
 class LocationFilter : public QWidget {
 	Q_OBJECT
 public:
-- 
2.1.3

From 6f734909e2d97bee42e05e61a568b67a062d0304 Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:36:49 -0200
Subject: [PATCH 15/16] Fix QString use

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qthelper.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qthelper.cpp b/qthelper.cpp
index 6769e8a..e165e85 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -308,7 +308,7 @@ extern "C" bool string_sequence_contains(const char *string_sequence, const char
 
 	QString stringSequence(string_sequence);
 	QStringList strings = stringSequence.split(",", QString::SkipEmptyParts);
-	Q_FOREACH (QString string, strings) {
+	Q_FOREACH (const QString& string, strings) {
 		if (string.trimmed().compare(QString(text).trimmed(), Qt::CaseInsensitive) == 0)
 			return true;
 	}
-- 
2.1.3

From b0463db839aa622b32c37cfc637d3a4f34d99e0e Mon Sep 17 00:00:00 2001
From: Tomaz Canabrava <[email protected]>
Date: Thu, 13 Nov 2014 17:37:54 -0200
Subject: [PATCH 16/16] Fix use of QString

We should use references when we are not wanting to make a copy
of it.

Signed-off-by: Tomaz Canabrava <[email protected]>
---
 qthelper.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/qthelper.cpp b/qthelper.cpp
index e165e85..0c1c68a 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -324,7 +324,6 @@ void selectedDivesGasUsed(QVector<QPair<QString, int> > &gasUsedOrdered)
 {
 	int i, j;
 	struct dive *d;
-	QString gas;
 	QMap<QString, int> gasUsed;
 	for_each_dive (i, d) {
 		if (!d->selected)
@@ -337,7 +336,7 @@ void selectedDivesGasUsed(QVector<QPair<QString, int> > &gasUsedOrdered)
 				gasUsed[gasName] += diveGases[j].mliter;
 			}
 	}
-	Q_FOREACH(gas, gasUsed.keys()) {
+	Q_FOREACH(const QString& gas, gasUsed.keys()) {
 		gasUsedOrdered.append(qMakePair(gas, gasUsed[gas]));
 	}
 	qSort(gasUsedOrdered.begin(), gasUsedOrdered.end(), lessThan);
-- 
2.1.3

_______________________________________________
subsurface mailing list
[email protected]
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to