diff options
author | Andrew den Exter <andrew.den-exter@nokia.com> | 2010-08-05 14:18:19 +1000 |
---|---|---|
committer | Andrew den Exter <andrew.den-exter@nokia.com> | 2010-08-05 14:18:19 +1000 |
commit | e3c2463502b1e4fc06fb4c78d4c9a2368e45ddf1 (patch) | |
tree | 0d72ea2762b1d5b543c34c61fdb3b0b8b41d41ff | |
parent | 9d48868867a286c6e20bac1682b695c101bb85bb (diff) |
Add thumbnails and cover art to the media browser.
-rw-r--r-- | examples/mediabrowser/albumview.cpp | 14 | ||||
-rw-r--r-- | examples/mediabrowser/coverartmodel.cpp | 83 | ||||
-rw-r--r-- | examples/mediabrowser/coverartmodel.h | 66 | ||||
-rw-r--r-- | examples/mediabrowser/mediabrowser.pro | 14 | ||||
-rw-r--r-- | examples/mediabrowser/photoview.cpp | 7 | ||||
-rw-r--r-- | examples/mediabrowser/thumbnailmodel.cpp | 147 | ||||
-rw-r--r-- | examples/mediabrowser/thumbnailmodel.h | 75 |
7 files changed, 398 insertions, 8 deletions
diff --git a/examples/mediabrowser/albumview.cpp b/examples/mediabrowser/albumview.cpp index 0d5b0bd0c0..c4afad5270 100644 --- a/examples/mediabrowser/albumview.cpp +++ b/examples/mediabrowser/albumview.cpp @@ -45,11 +45,20 @@ #include <QtGui> #include <qdocumentgallery.h> -#include <qgalleryquerymodel.h> + +#if defined(Q_WS_MAEMO_5) +#include "coverartmodel.h" +#else +#include <thumbnailmodel.h> +#endif AlbumView::AlbumView(QAbstractGallery *gallery, QWidget *parent, Qt::WindowFlags flags) : GalleryView(parent, flags) +#if defined(Q_WS_MAEMO_5) + , model(new CoverArtModel(gallery)) +#else , model(new QGalleryQueryModel(gallery)) +#endif { model->setRootType(QDocumentGallery::Album); @@ -63,7 +72,7 @@ AlbumView::AlbumView(QAbstractGallery *gallery, QWidget *parent, Qt::WindowFlags << QDocumentGallery::title); QListView *view = new QListView; - view->setIconSize(QSize(124, 124)); + view->setIconSize(ThumbnailModel::thumbnailSize); view->setFlow(QListView::LeftToRight); view->setViewMode(QListView::IconMode); view->setSpacing(4); @@ -72,7 +81,6 @@ AlbumView::AlbumView(QAbstractGallery *gallery, QWidget *parent, Qt::WindowFlags view->setItemDelegate(new AlbumDelegate(this)); connect(view, SIGNAL(activated(QModelIndex)), this, SLOT(activated(QModelIndex))); - QBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); layout->setSpacing(0); diff --git a/examples/mediabrowser/coverartmodel.cpp b/examples/mediabrowser/coverartmodel.cpp new file mode 100644 index 0000000000..b7f116daaf --- /dev/null +++ b/examples/mediabrowser/coverartmodel.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "coverartmodel.h" + +#include "albumdelegate.h" + +#include <QtCore/qcryptographichash.h> +#include <QtCore/qdir.h> +#include <QtCore/qurl.h> + +#define QT_GALLERY_MEDIA_ART_ILLEGAL_CHARACTERS \ + "\\(.*\\)|\\{.*\\}|\\[.*\\]|<.*>|[\\(\\)_\\{\\}\\[\\]\\!@#$\\^&\\*\\+\\=\\|\\\\/\"'\\?~`]" + +CoverArtModel::CoverArtModel(QAbstractGallery *gallery, QObject *parent) + : ThumbnailModel(gallery, parent) + , illegalCharacters(QLatin1String(QT_GALLERY_MEDIA_ART_ILLEGAL_CHARACTERS)) + , whitespace(QCryptographicHash::hash(" ", QCryptographicHash::Md5).toHex()) +{ +} + +QString CoverArtModel::imagePath(const QModelIndex &index) const +{ + QString title = index.data(Qt::DisplayRole).toString(); + QString artist = index.data(AlbumDelegate::Artist).toString(); + + QString fileName = QDir::homePath() + + QLatin1String("/.cache/media-art/album-") + + hash(artist) + + QLatin1Char('-') + + hash(title) + + QLatin1String(".jpeg"); + + return thumbnailPath(QUrl::fromLocalFile(fileName)); +} + +QString CoverArtModel::hash(const QString &identifier) const +{ + if (identifier.isEmpty()) { + return whitespace; + } else { + return QCryptographicHash::hash( + identifier.toLower().remove(illegalCharacters).simplified().toUtf8(), + QCryptographicHash::Md5).toHex(); + } +} diff --git a/examples/mediabrowser/coverartmodel.h b/examples/mediabrowser/coverartmodel.h new file mode 100644 index 0000000000..d2329ec7bb --- /dev/null +++ b/examples/mediabrowser/coverartmodel.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COVERARTMODEL_H +#define COVERARTMODEL_H + +#include "thumbnailmodel.h" + +#include <QtCore/qregexp.h> + +QTM_USE_NAMESPACE + +class CoverArtModel : public ThumbnailModel +{ + Q_OBJECT +public: + CoverArtModel(QAbstractGallery *gallery, QObject *parent = 0); + +protected: + QString imagePath(const QModelIndex &index) const; + +private: + QString hash(const QString &identifier) const; + + QRegExp illegalCharacters; + QString whitespace; +}; + +#endif diff --git a/examples/mediabrowser/mediabrowser.pro b/examples/mediabrowser/mediabrowser.pro index e98181679d..cdfedeb02d 100644 --- a/examples/mediabrowser/mediabrowser.pro +++ b/examples/mediabrowser/mediabrowser.pro @@ -17,7 +17,8 @@ HEADERS = \ galleryview.h \ photodelegate.h \ photoview.h \ - songview.h + songview.h \ + thumbnailmodel.h SOURCES = \ albumdelegate.cpp \ @@ -29,4 +30,13 @@ SOURCES = \ main.cpp \ photodelegate.cpp \ photoview.cpp \ - songview.cpp + songview.cpp \ + thumbnailmodel.cpp + +maemo5 { + HEADERS += \ + coverartmodel.h + + SOURCES += \ + coverartmodel.cpp +} diff --git a/examples/mediabrowser/photoview.cpp b/examples/mediabrowser/photoview.cpp index 92c7eeb969..8111124ad1 100644 --- a/examples/mediabrowser/photoview.cpp +++ b/examples/mediabrowser/photoview.cpp @@ -41,15 +41,16 @@ #include "photoview.h" #include "photodelegate.h" +#include "thumbnailmodel.h" #include <QtGui> #include <qdocumentgallery.h> -#include <qgalleryquerymodel.h> + PhotoView::PhotoView(QAbstractGallery *gallery, QWidget *parent, Qt::WindowFlags flags) : GalleryView(parent, flags) - , model(new QGalleryQueryModel(gallery)) + , model(new ThumbnailModel(gallery)) { model->setRootType(QDocumentGallery::Image); @@ -61,7 +62,7 @@ PhotoView::PhotoView(QAbstractGallery *gallery, QWidget *parent, Qt::WindowFlags << QDocumentGallery::title); QListView *view = new QListView; - view->setIconSize(QSize(124, 124)); + view->setIconSize(ThumbnailModel::thumbnailSize); view->setFlow(QListView::TopToBottom); view->setViewMode(QListView::IconMode); view->setUniformItemSizes(true); diff --git a/examples/mediabrowser/thumbnailmodel.cpp b/examples/mediabrowser/thumbnailmodel.cpp new file mode 100644 index 0000000000..0feca29196 --- /dev/null +++ b/examples/mediabrowser/thumbnailmodel.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <thumbnailmodel.h> + +#include <QtCore/qcryptographichash.h> +#include <QtCore/qdir.h> +#include <QtCore/qtconcurrentrun.h> +#include <QtCore/qurl.h> +#include <QtGui/qimagereader.h> + +#if defined(Q_WS_MAEMO_5) +const QSize ThumbnailModel::thumbnailSize(124, 124); +#else +const QSize ThumbnailModel::thumbnailSize(128, 128); +#endif + +ThumbnailModel::ThumbnailModel(QAbstractGallery *gallery, QObject *parent) + : QGalleryQueryModel(gallery, parent) +{ +} + +ThumbnailModel::~ThumbnailModel() +{ +} + +QVariant ThumbnailModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::DecorationRole && index.isValid()) { + QString id = itemId(index).toString(); + + QFutureWatcher<QImage> *future = cache.object(id); + + if (!future) { + future = new QFutureWatcher<QImage>; + + QString path = imagePath(index); + + if (!path.isEmpty()) { + future->setFuture(QtConcurrent::run(ThumbnailModel::load, path)); + + connect(future, SIGNAL(finished()), this, SLOT(thumbnailLoaded())); + } + + cache.insert(id, future); + } + + return future->result(); + } else { + return QGalleryQueryModel::data(index, role); + } +} + +QString ThumbnailModel::imagePath(const QModelIndex &index) const +{ + QUrl url = itemUrl(index); + + return url.isValid() ? thumbnailPath(url) : QString(); +} + +QString ThumbnailModel::thumbnailPath(const QUrl &url) const +{ +#if defined(Q_OS_UNIX) && !(defined(Q_OS_SYMBIAN) || defined(Q_OS_MAC)) +#if defined(Q_WS_MAEMO_5) + QString thumbnailPath = QDir::homePath() + + QLatin1String("/.thumbnails/cropped/") + + QCryptographicHash::hash(url.toString().toUtf8(), QCryptographicHash::Md5).toHex() + + QLatin1String(".jpeg"); +#else + QString thumbnailPath = QDir::homePath() + + QLatin1String("/.thumbnails/normal/") + + QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Md5).toHex() + + QLatin1String(".png"); +#endif + if (QFile::exists(thumbnailPath)) + return thumbnailPath; +#endif + + return url.path(); +} + +void ThumbnailModel::thumbnailLoaded() +{ + emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() -1)); +} + +QImage ThumbnailModel::load(const QString &fileName) +{ + QImageReader reader(fileName); + reader.setQuality(25); + + if (reader.supportsOption(QImageIOHandler::Size)) { + QSize size = reader.size(); + + if (!reader.supportsOption(QImageIOHandler::ScaledSize) + && (size.width() > 1280 || size.height() > 1280)) { + return QImage(); + } + + if (size.width() > thumbnailSize.width() || size.height() > thumbnailSize.height()) + size.scale(thumbnailSize, Qt::KeepAspectRatio); + + reader.setScaledSize(size); + } else { + reader.setScaledSize(thumbnailSize); + } + + return reader.read(); +} + diff --git a/examples/mediabrowser/thumbnailmodel.h b/examples/mediabrowser/thumbnailmodel.h new file mode 100644 index 0000000000..0815148522 --- /dev/null +++ b/examples/mediabrowser/thumbnailmodel.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef THUMBNAILMODEL_H +#define THUMBNAILMODEL_H + +#include <qgalleryquerymodel.h> + +#include <QtCore/qcache.h> +#include <QtCore/qfuturewatcher.h> + +QTM_USE_NAMESPACE + +class ThumbnailModel : public QGalleryQueryModel +{ + Q_OBJECT +public: + ThumbnailModel(QAbstractGallery *gallery, QObject *parent = 0); + ~ThumbnailModel(); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + static const QSize thumbnailSize; + +protected: + virtual QString imagePath(const QModelIndex &index) const; + + QString thumbnailPath(const QUrl &url) const; +private slots: + void thumbnailLoaded(); + +private: + static QImage load(const QString &fileName); + + mutable QCache<QString, QFutureWatcher<QImage> > cache; +}; + +#endif |