Files
cantata/gui/cachesettings.cpp
2013-08-08 19:16:16 +00:00

310 lines
10 KiB
C++

/*
* Cantata
*
* Copyright (c) 2011-2013 Craig Drummond <craig.p.drummond@gmail.com>
*
*/
/* This file is part of Clementine.
Copyright 2010, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cachesettings.h"
#include "localize.h"
#include "artistview.h"
#include "albumview.h"
#include "songview.h"
#include "contextwidget.h"
#include "covers.h"
#include "musiclibrarymodel.h"
#include "utils.h"
#include "messagebox.h"
#include "config.h"
#include "thread.h"
#include "settings.h"
#include "treeview.h"
#include "streamsmodel.h"
#include <QLabel>
#include <QPushButton>
#include <QStyle>
#include <QGridLayout>
#include <QFileInfo>
#include <QDir>
#include <QList>
#include <QHeaderView>
static const int constMaxRecurseLevel=4;
static void calculate(const QString &d, const QStringList &types, int &items, int &space, int level=0)
{
if (!d.isEmpty() && level<constMaxRecurseLevel) {
QDir dir(d);
if (dir.exists()) {
QFileInfoList files=dir.entryInfoList(types, QDir::Files|QDir::NoDotAndDotDot);
foreach (const QFileInfo &file, files) {
space+=file.size();
}
items+=files.count();
QFileInfoList dirs=dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
foreach (const QFileInfo &subDir, dirs) {
calculate(subDir.absoluteFilePath(), types, items, space, level+1);
}
}
}
}
static void deleteAll(const QString &d, const QStringList &types, int level=0)
{
if (!d.isEmpty() && level<constMaxRecurseLevel) {
QDir dir(d);
if (dir.exists()) {
QFileInfoList dirs=dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
foreach (const QFileInfo &subDir, dirs) {
deleteAll(subDir.absoluteFilePath(), types, level+1);
}
QFileInfoList files=dir.entryInfoList(types, QDir::Files|QDir::NoDotAndDotDot);
foreach (const QFileInfo &file, files) {
QFile::remove(file.absoluteFilePath());
}
if (0!=level) {
QString dirName=dir.dirName();
if (!dirName.isEmpty()) {
dir.cdUp();
dir.rmdir(dirName);
}
}
}
}
}
CacheItemCounter::CacheItemCounter(const QString &name, const QString &d, const QStringList &t)
: dir(d)
, types(t)
{
thread=new Thread(name+" CacheCleaner");
moveToThread(thread);
thread->start();
}
CacheItemCounter::~CacheItemCounter()
{
if (thread) {
thread->stop();
}
}
void CacheItemCounter::getCount()
{
int items=0;
int space=0;
calculate(dir, types, items, space);
emit count(items, space);
}
void CacheItemCounter::deleteAll()
{
::deleteAll(dir, types);
getCount();
}
CacheItem::CacheItem(const QString &title, const QString &d, const QStringList &t, QTreeWidget *p)
: QTreeWidgetItem(p, QStringList() << title)
, counter(new CacheItemCounter(title, d, t))
, empty(true)
{
connect(this, SIGNAL(getCount()), counter, SLOT(getCount()), Qt::QueuedConnection);
connect(this, SIGNAL(deleteAll()), counter, SLOT(deleteAll()), Qt::QueuedConnection);
connect(counter, SIGNAL(count(int, int)), this, SLOT(update(int, int)), Qt::QueuedConnection);
connect(this, SIGNAL(updated()), p, SIGNAL(itemSelectionChanged()));
}
CacheItem::~CacheItem()
{
delete counter;
}
void CacheItem::update(int itemCount, int space)
{
setText(1, QString::number(itemCount));
setText(2, Utils::formatByteSize(space));
empty=0==itemCount;
setStatus();
emit updated();
}
void CacheItem::setStatus(const QString &str)
{
QFont f(font(0));
if (!str.isEmpty()) {
f.setItalic(true);
setText(1, str);
setText(2, str);
}
setFont(1, f);
setFont(2, f);
}
void CacheItem::clean()
{
setStatus(i18n("Deleting..."));
emit deleteAll();
}
void CacheItem::calculate()
{
setStatus(i18n("Calculating..."));
emit getCount();
}
#if QT_VERSION < 0x050000
static inline void setResizeMode(QHeaderView *hdr, int idx, QHeaderView::ResizeMode mode)
{
hdr->setResizeMode(idx, mode);
}
#else
static inline void setResizeMode(QHeaderView *hdr, int idx, QHeaderView::ResizeMode mode)
{
hdr->setSectionResizeMode(idx, mode);
}
#endif
CacheTree::CacheTree(QWidget *parent)
: QTreeWidget(parent)
, calculated(false)
{
setHeaderLabels(QStringList() << i18n("Name") << i18n("Item Count") << i18n("Space Used"));
setAllColumnsShowFocus(true);
setSelectionMode(QAbstractItemView::ExtendedSelection);
setRootIsDecorated(false);
setSortingEnabled(false);
//setSortingEnabled(true);
//sortByColumn(0, Qt::AscendingOrder);
setResizeMode(header(), 0, QHeaderView::Stretch);
setResizeMode(header(), 1, QHeaderView::Stretch);
setResizeMode(header(), 2, QHeaderView::Stretch);
header()->setStretchLastSection(true);
setAlternatingRowColors(false);
setItemDelegate(new SimpleTreeViewDelegate(this));
}
CacheTree::~CacheTree()
{
}
void CacheTree::showEvent(QShowEvent *e)
{
if (!calculated) {
for (int i=0; i<topLevelItemCount(); ++i) {
((CacheItem *)topLevelItem(i))->calculate();
}
calculated=true;
}
QTreeWidget::showEvent(e);
}
CacheSettings::CacheSettings(QWidget *parent)
: QWidget(parent)
{
int spacing=Utils::layoutSpacing(this);
QGridLayout *layout=new QGridLayout(this);
layout->setMargin(0);
int row=0;
int col=0;
QLabel *label=new QLabel(i18n("To speed up loading of the music library, Cantata caches a local copy of the MPD listing. Cantata might also have cached "
"covers, or lyrics, if these have been downloaded and could not be saved into the MPD folder (because Cantata cannot access it, "
"or you have configured Cantata to not save these items there). Below is a summary of Cantata's cache usage."), this);
label->setWordWrap(true);
layout->addWidget(label, row++, col, 1, 2);
layout->addItem(new QSpacerItem(spacing, spacing, QSizePolicy::Fixed, QSizePolicy::Fixed), row++, 0);
tree=new CacheTree(this);
layout->addWidget(tree, row++, col, 1, 2);
new CacheItem(i18n("Music Library"), Utils::cacheDir(MusicLibraryModel::constLibraryCache, false),
QStringList() << "*"+MusicLibraryModel::constLibraryExt << "*"+MusicLibraryModel::constLibraryCompressedExt, tree);
new CacheItem(i18n("Covers"), Utils::cacheDir(Covers::constCoverDir, false), QStringList() << "*.jpg" << "*.png", tree);
new CacheItem(i18n("Backdrops"), Utils::cacheDir(ContextWidget::constCacheDir, false), QStringList() << "*.jpg" << "*.png", tree);
new CacheItem(i18n("Lyrics"), Utils::cacheDir(SongView::constLyricsDir, false), QStringList() << "*"+SongView::constExtension, tree);
new CacheItem(i18n("Artist Information"), Utils::cacheDir(ArtistView::constCacheDir, false), QStringList() << "*"+ArtistView::constInfoExt
<< "*"+ArtistView::constSimilarInfoExt << "*.json.gz" << "*.jpg" << "*.png", tree);
new CacheItem(i18n("Album Information"), Utils::cacheDir(AlbumView::constCacheDir, false), QStringList() << "*"+AlbumView::constInfoExt << "*.jpg" << "*.png", tree);
new CacheItem(i18n("Streams"), Utils::cacheDir(StreamsModel::constCacheDir, false), QStringList() << "*"+StreamsModel::constCacheExt, tree);
new CacheItem(i18n("Jamendo"), Utils::cacheDir("jamendo", false), QStringList() << "*"+MusicLibraryModel::constLibraryCompressedExt << "*.jpg" << "*.png", tree);
new CacheItem(i18n("Magnatune"), Utils::cacheDir("magnatune", false), QStringList() << "*"+MusicLibraryModel::constLibraryCompressedExt<< "*.jpg" << "*.png", tree);
button=new QPushButton(i18n("Delete All"), this);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Fixed), row++, 0);
layout->addWidget(button, row, 1, 1, 1);
button->setEnabled(false);
connect(tree, SIGNAL(itemSelectionChanged()), this, SLOT(controlButton()));
connect(button, SIGNAL(clicked()), this, SLOT(deleteAll()));
}
CacheSettings::~CacheSettings()
{
}
void CacheSettings::controlButton()
{
button->setEnabled(false);
for (int i=0; i<tree->topLevelItemCount(); ++i) {
CacheItem *item=(CacheItem *)tree->topLevelItem(i);
if (item->isSelected() && !item->isEmpty()) {
button->setEnabled(true);
break;
}
}
}
void CacheSettings::deleteAll()
{
QList<CacheItem *> toDelete;
for (int i=0; i<tree->topLevelItemCount(); ++i) {
CacheItem *item=(CacheItem *)tree->topLevelItem(i);
if (item->isSelected() && !item->isEmpty()) {
toDelete.append(item);
}
}
if (!toDelete.isEmpty()) {
if (1==toDelete.count()) {
if (MessageBox::Yes==MessageBox::warningYesNo(this, i18n("Delete all '%1' items?", toDelete.at(0)->name()),
i18n("Delete Cache Items"), StdGuiItem::del(), StdGuiItem::cancel())) {
toDelete.first()->clean();
}
} else if (toDelete.count()>1) {
QString items;
foreach (CacheItem *i, toDelete) {
items+="<li>"+i->name()+"</li>";
}
if (MessageBox::No==MessageBox::warningYesNo(this, i18n("<p>Delete all from the following?<ul>%1</ul></p>", items),
i18n("Delete Cache Items"), StdGuiItem::del(), StdGuiItem::cancel())) {
return;
}
foreach (CacheItem *i, toDelete) {
i->clean();
}
}
}
}