diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7f143487d..d2431e875 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -73,6 +73,7 @@ set(SOURCES core/gnomeglobalshortcutbackend.cpp core/logging.cpp core/mergedproxymodel.cpp + core/multisortfilterproxy.cpp core/musicstorage.cpp core/network.cpp core/networkproxyfactory.cpp diff --git a/src/core/multisortfilterproxy.cpp b/src/core/multisortfilterproxy.cpp new file mode 100644 index 000000000..f24143179 --- /dev/null +++ b/src/core/multisortfilterproxy.cpp @@ -0,0 +1,65 @@ +#include "logging.h" +#include "multisortfilterproxy.h" + +#include +#include +#include + +MultiSortFilterProxy::MultiSortFilterProxy(QObject* parent) + : QSortFilterProxyModel(parent) +{ +} + +void MultiSortFilterProxy::AddSortSpec(int role, Qt::SortOrder order) { + sorting_ << SortSpec(role, order); +} + +bool MultiSortFilterProxy::lessThan(const QModelIndex& left, + const QModelIndex& right) const { + foreach (const SortSpec& spec, sorting_) { + const int ret = compare(left.data(spec.first), right.data(spec.first)); + + if (ret < 0) { + return spec.second == Qt::AscendingOrder; + } else if (ret > 0) { + return spec.second != Qt::AscendingOrder; + } + } + + return left.row() < right.row(); +} + +int MultiSortFilterProxy::compare(const QVariant& left, const QVariant& right) const { + // Copied from the QSortFilterProxyModel::lessThan implementation, but returns + // -1, 0 or 1 instead of true or false. + + #define docompare(left, right) \ + if (left < right) return -1; \ + if (left > right) return 1; \ + return 0; + + switch (left.userType()) { + case QVariant::Invalid: + return (right.type() != QVariant::Invalid) ? -1 : 0; + case QVariant::Int: docompare(left.toInt(), right.toInt()); + case QVariant::UInt: docompare(left.toUInt(), right.toUInt()); + case QVariant::LongLong: docompare(left.toLongLong(), right.toLongLong()); + case QVariant::ULongLong: docompare(left.toULongLong(), right.toULongLong()); + case QMetaType::Float: docompare(left.toFloat(), right.toFloat()); + case QVariant::Double: docompare(left.toDouble(), right.toDouble()); + case QVariant::Char: docompare(left.toChar(), right.toChar()); + case QVariant::Date: docompare(left.toDate(), right.toDate()); + case QVariant::Time: docompare(left.toTime(), right.toTime()); + case QVariant::DateTime: docompare(left.toDateTime(), right.toDateTime()); + case QVariant::String: + default: + if (isSortLocaleAware()) + return left.toString().localeAwareCompare(right.toString()); + else + return left.toString().compare(right.toString(), sortCaseSensitivity()); + } + + #undef docompare + + return 0; +} diff --git a/src/core/multisortfilterproxy.h b/src/core/multisortfilterproxy.h new file mode 100644 index 000000000..89058e325 --- /dev/null +++ b/src/core/multisortfilterproxy.h @@ -0,0 +1,22 @@ +#ifndef MULTISORTFILTERPROXY_H +#define MULTISORTFILTERPROXY_H + +#include + +class MultiSortFilterProxy : public QSortFilterProxyModel { +public: + MultiSortFilterProxy(QObject* parent = NULL); + + void AddSortSpec(int role, Qt::SortOrder order = Qt::AscendingOrder); + +protected: + bool lessThan(const QModelIndex& left, const QModelIndex& right) const; + +private: + int compare(const QVariant& left, const QVariant& right) const; + + typedef QPair SortSpec; + QList sorting_; +}; + +#endif // MULTISORTFILTERPROXY_H diff --git a/src/ui/albumcoversearcher.cpp b/src/ui/albumcoversearcher.cpp index 65def0088..37255b13f 100644 --- a/src/ui/albumcoversearcher.cpp +++ b/src/ui/albumcoversearcher.cpp @@ -42,6 +42,7 @@ AlbumCoverSearcher::AlbumCoverSearcher(const QIcon& no_cover_icon, QWidget* pare ui_->busy->hide(); ui_->covers->set_header_text(tr("Covers from %1")); + ui_->covers->AddSortSpec(Role_ImageDimensions, Qt::DescendingOrder); ui_->covers->setModel(model_); loader_->Start(true); @@ -162,6 +163,7 @@ void AlbumCoverSearcher::ImageLoaded(quint64 id, const QImage& image) { QStandardItem* item = cover_loading_tasks_.take(id); item->setData(true, Role_ImageFetchFinished); + item->setData(image.width() * image.height(), Role_ImageDimensions); item->setIcon(icon); item->setToolTip(item->text() + " (" + QString::number(image.width()) + "x" + QString::number(image.height()) + ")"); diff --git a/src/ui/albumcoversearcher.h b/src/ui/albumcoversearcher.h index e566997f7..e3d23a04c 100644 --- a/src/ui/albumcoversearcher.h +++ b/src/ui/albumcoversearcher.h @@ -46,6 +46,7 @@ public: Role_ImageURL = Qt::UserRole + 1, Role_ImageRequestId, Role_ImageFetchFinished, + Role_ImageDimensions, }; void Init(AlbumCoverFetcher* fetcher); diff --git a/src/widgets/groupediconview.cpp b/src/widgets/groupediconview.cpp index ad959598e..7d7d6288b 100644 --- a/src/widgets/groupediconview.cpp +++ b/src/widgets/groupediconview.cpp @@ -16,6 +16,7 @@ */ #include "groupediconview.h" +#include "core/multisortfilterproxy.h" #include #include @@ -29,7 +30,7 @@ const int GroupedIconView::kBarMarginTop = 3; GroupedIconView::GroupedIconView(QWidget* parent) : QListView(parent), - proxy_model_(new QSortFilterProxyModel(this)), + proxy_model_(new MultiSortFilterProxy(this)), default_header_height_(fontMetrics().height() + kBarMarginTop + kBarThickness), header_spacing_(10), @@ -43,12 +44,16 @@ GroupedIconView::GroupedIconView(QWidget* parent) setWordWrap(true); setDragEnabled(false); - proxy_model_->setSortRole(Role_Group); + proxy_model_->AddSortSpec(Role_Group); proxy_model_->setDynamicSortFilter(true); connect(proxy_model_, SIGNAL(modelReset()), SLOT(LayoutItems())); } +void GroupedIconView::AddSortSpec(int role, Qt::SortOrder order) { + proxy_model_->AddSortSpec(role, order); +} + void GroupedIconView::setModel(QAbstractItemModel* model) { proxy_model_->setSourceModel(model); proxy_model_->sort(0); diff --git a/src/widgets/groupediconview.h b/src/widgets/groupediconview.h index 4ff528683..2a0ccc6cd 100644 --- a/src/widgets/groupediconview.h +++ b/src/widgets/groupediconview.h @@ -20,7 +20,7 @@ #include -class QSortFilterProxyModel; +class MultiSortFilterProxy; class GroupedIconView : public QListView { @@ -45,6 +45,8 @@ public: Role_Group = 1158300, }; + void AddSortSpec(int role, Qt::SortOrder order = Qt::AscendingOrder); + int header_spacing() const { return header_spacing_; } int header_indent() const { return header_indent_; } int item_indent() const { return item_indent_; } @@ -95,7 +97,7 @@ private: // Returns the index of the item above (d=-1) or below (d=+1) the given item. int IndexAboveOrBelow(int index, int d) const; - QSortFilterProxyModel* proxy_model_; + MultiSortFilterProxy* proxy_model_; QVector visual_rects_; QVector
headers_;