Merge branch 'master' into 1180-local-fs-browsing

This commit is contained in:
Craig Drummond
2018-02-06 19:23:13 +00:00
8 changed files with 94 additions and 44 deletions

View File

@@ -56,7 +56,8 @@
40. Add option to use 'Original Year' to display and sort albums.
41. Sort folder view items, as MPD does not seem to sort playlist names.
42. In folder view, allow to add folders and files at the same time.
43. Add root and home local browse models, allowing to add local files to play
43. Support dragging m3u and m3u8 playlists onto playqueue.
44. Add root and home local browse models, allowing to add local files to play
queue.
2.2.0

View File

@@ -800,7 +800,7 @@ QList<LibraryDb::Album> LibraryDb::getAlbums(const QString &artistId, const QStr
s.albumartist=Song::variousArtists();
s.year = s.origYear = 0;
}
album=s.displayAlbum();
album=s.albumName();
int time=query.value(col++).toInt();
int lastModified=wantModified ? query.value(col++).toInt() : 0;
QString artist=wantArtist ? query.value(col++).toString() : QString();

View File

@@ -51,6 +51,8 @@
#endif
#include <QPalette>
#include <QFont>
#include <QFile>
#include <QDir>
#include <QModelIndex>
#include <QMimeData>
#include <QTextStream>
@@ -78,17 +80,46 @@ static const QLatin1String constSortByPerformerKey("performer");
static const QLatin1String constSortByTitleKey("title");
static const QLatin1String constSortByNumberKey("track");
static QSet<QString> constPlaylists = QSet<QString>() << QLatin1String("m3u") << QLatin1String("m3u8");
QSet<QString> PlayQueueModel::constFileExtensions = QSet<QString>()
<< QLatin1String("mp3") << QLatin1String("ogg") << QLatin1String("flac") << QLatin1String("wma") << QLatin1String("m4a")
<< QLatin1String("m4b") << QLatin1String("mp4") << QLatin1String("m4p") << QLatin1String("wav") << QLatin1String("wv")
<< QLatin1String("wvp") << QLatin1String("aiff") << QLatin1String("aif") << QLatin1String("aifc") << QLatin1String("ape")
<< QLatin1String("spx") << QLatin1String("tta") << QLatin1String("mpc") << QLatin1String("mpp") << QLatin1String("mp+")
<< QLatin1String("dff") << QLatin1String("dsf");
<< QLatin1String("dff") << QLatin1String("dsf")
// And playlists...
<< QLatin1String("m3u") << QLatin1String("m3u8");
static bool checkExtension(const QString &file)
static bool checkExtension(const QString &file, const QSet<QString> &exts = PlayQueueModel::constFileExtensions)
{
int pos=file.lastIndexOf('.');
return pos>1 ? PlayQueueModel::constFileExtensions.contains(file.mid(pos+1).toLower()) : false;
return pos>1 ? exts.contains(file.mid(pos+1).toLower()) : false;
}
static QStringList expandPlaylist(const QString &playlist)
{
QStringList files;
QFile f(playlist);
QDir dir(Utils::getDir(playlist));
if (f.open(QIODevice::ReadOnly|QIODevice::Text)) {
QTextStream in(&f);
while (!in.atEnd()) {
QString line = in.readLine();
if (!line.startsWith(QLatin1Char('#'))) {
if (checkExtension(line)) {
QString path = dir.filePath(line);
if (QFile::exists(path)) { // Relative
files.append(path);
} else if (QFile::exists(line)) { // Absolute
files.append(line);
}
}
}
}
f.close();
}
return files;
}
static QStringList listFiles(const QDir &d, int level=5)
@@ -98,6 +129,8 @@ static QStringList listFiles(const QDir &d, int level=5)
for (const auto &f: d.entryInfoList(QDir::Files|QDir::Dirs|QDir::NoDotAndDotDot|QDir::NoSymLinks)) {
if (f.isDir()) {
files += listFiles(QDir(f.absoluteFilePath()), level-1);
} else if (checkExtension(f.fileName(), constPlaylists)) {
files += expandPlaylist(f.absoluteFilePath());
} else if (checkExtension(f.fileName())) {
files.append(f.absoluteFilePath());
}
@@ -126,6 +159,8 @@ static QStringList parseUrls(const QStringList &urls, bool percentEncoded)
if (d.exists()) {
files = listFiles(d);
} else if (checkExtension(u.path(), constPlaylists)) {
files += expandPlaylist(u.path());
} else if (checkExtension(u.path())) {
files.append(u.path());
}

View File

@@ -34,6 +34,7 @@ namespace Cantata {
Role_BriefMainText,
Role_SubText,
Role_TitleText,
Role_TitleSubText,
Role_TitleActions,
Role_Image,
Role_ListImage, // Should image been shown in list/tree view?

View File

@@ -177,11 +177,10 @@ void SqlLibraryModel::libraryUpdated()
QList<LibraryDb::Album> albums=db->getAlbums(QString(), QString(), albumSort);
if (!albums.isEmpty()) {
for (const LibraryDb::Album &album: albums) {
QString trackInfo = tr("%n Tracks (%1)", "", album.trackCount).arg(Utils::formatTime(album.duration, true));
root->add(new AlbumItem(T_Album==tl && album.identifyById ? QString() : album.artist,
album.id, Song::displayAlbum(album.name, album.year),
T_Album==tl
? album.artist
: tr("%n Tracks (%1)", "", album.trackCount).arg(Utils::formatTime(album.duration, true)), root));
T_Album==tl ? album.artist : trackInfo, T_Album==tl ? trackInfo : QString(), root));
}
}
break;
@@ -366,11 +365,18 @@ QVariant SqlLibraryModel::data(const QModelIndex &index, int role) const
(0==item->getChildCount()
? item->getText()
: (item->getText()+"<br/>"+data(index, Cantata::Role_SubText).toString()));
case Cantata::Role_TitleSubText:
if (T_Album==tl && T_Album==item->getType()) {
return static_cast<AlbumItem *>(item)->getTitleSub();
}
case Cantata::Role_SubText:
return item->getSubText();
case Cantata::Role_ListImage:
return T_Album==item->getType();
case Cantata::Role_TitleText:
if (T_Album==item->getType()) {
return tr("%1 by %2").arg(item->getText()).arg(T_Album==tl ? item->getSubText() : item->getParent()->getText());
}
return item->getText();
case Cantata::Role_TitleActions:
switch (item->getType()) {

View File

@@ -112,15 +112,18 @@ public:
class AlbumItem : public CollectionItem {
public:
AlbumItem(const QString &ar, const QString &i, const QString &txt=QString(), const QString &sub=QString(), CollectionItem *p=nullptr)
: CollectionItem(T_Album, i, txt, sub, p), artistId(ar) { }
AlbumItem(const QString &ar, const QString &i, const QString &txt=QString(), const QString &sub=QString(),
const QString &tSub=QString(), CollectionItem *p=nullptr)
: CollectionItem(T_Album, i, txt, sub, p), artistId(ar), titleSub(tSub) { }
~AlbumItem() override { }
const QString & getArtistId() const { return artistId; }
const QString getUniqueId() const override { return artistId+getId(); }
const QString & getTitleSub() const {return titleSub; }
private:
QString artistId;
QString titleSub;
};
SqlLibraryModel(LibraryDb *d, QObject *p, Type top=T_Artist);

View File

@@ -1609,10 +1609,14 @@ void ItemView::setTitle()
if (!model) {
return;
}
QString sub = model->data(index, Cantata::Role_TitleSubText).toString();
if (sub.isEmpty()) {
sub = model->data(index, Cantata::Role_SubText).toString();
}
title->update(model->data(index, Mode_IconTop==mode ? Cantata::Role_GridCoverSong : Cantata::Role_CoverSong).value<Song>(),
model->data(index, Qt::DecorationRole).value<QIcon>(),
model->data(index, Cantata::Role_TitleText).toString(),
model->data(index, Cantata::Role_SubText).toString(),
sub,
model->data(index, Cantata::Role_TitleActions).toBool());
}

View File

@@ -85,11 +85,11 @@ TitleWidget::TitleWidget(QWidget *p)
textLayout->addWidget(mainText);
textLayout->addWidget(subText);
layout->addItem(textLayout, 0, 3, 2, 1);
mainText->installEventFilter(this);
subText->installEventFilter(this);
image->installEventFilter(this);
installEventFilter(this);
setAttribute(Qt::WA_Hover);
mainText->setAttribute(Qt::WA_TransparentForMouseEvents);
subText->setAttribute(Qt::WA_TransparentForMouseEvents);
image->setAttribute(Qt::WA_TransparentForMouseEvents);
viewport()->installEventFilter(this);
viewport()->setAttribute(Qt::WA_Hover);
connect(Covers::self(), SIGNAL(cover(Song,QImage,QString)), this, SLOT(coverRetrieved(Song,QImage,QString)));
connect(Covers::self(), SIGNAL(coverUpdated(Song,QImage,QString)), this, SLOT(coverRetrieved(Song,QImage,QString)));
connect(Covers::self(), SIGNAL(artistImage(Song,QImage,QString)), this, SLOT(coverRetrieved(Song,QImage,QString)));
@@ -169,9 +169,9 @@ void TitleWidget::update(const Song &sng, const QIcon &icon, const QString &text
bool TitleWidget::eventFilter(QObject *o, QEvent *event)
{
switch(event->type()) {
case QEvent::HoverEnter:
if (isEnabled() && o==this) {
if (isEnabled()) {
switch(event->type()) {
case QEvent::HoverEnter: {
QPalette pal = qApp->palette();
#ifdef Q_OS_MAC
QColor col(OSXStyle::self()->viewPalette().color(QPalette::Highlight));
@@ -181,38 +181,38 @@ bool TitleWidget::eventFilter(QObject *o, QEvent *event)
col.setAlphaF(0.2);
pal.setColor(QPalette::Base, col);
setPalette(pal);
break;
}
break;
case QEvent::HoverLeave:
if (isEnabled() && o==this) {
case QEvent::HoverLeave: {
QPalette pal = qApp->palette();
QColor col(pal.color(QPalette::Base));
pal.setColor(QPalette::Base, col);
setPalette(pal);
break;
}
break;
case QEvent::MouseButtonPress:
if (Qt::LeftButton==static_cast<QMouseEvent *>(event)->button() && Qt::NoModifier==static_cast<QMouseEvent *>(event)->modifiers()) {
QPalette pal = qApp->palette();
#ifdef Q_OS_MAC
QColor col(OSXStyle::self()->viewPalette().color(QPalette::Highlight));
#else
QColor col(pal.color(QPalette::Highlight));
#endif
col.setAlphaF(0.5);
pal.setColor(QPalette::Base, col);
setPalette(pal);
pressed=true;
case QEvent::MouseButtonPress:
if (Qt::LeftButton==static_cast<QMouseEvent *>(event)->button() && Qt::NoModifier==static_cast<QMouseEvent *>(event)->modifiers()) {
QPalette pal = qApp->palette();
#ifdef Q_OS_MAC
QColor col(OSXStyle::self()->viewPalette().color(QPalette::Highlight));
#else
QColor col(pal.color(QPalette::Highlight));
#endif
col.setAlphaF(0.5);
pal.setColor(QPalette::Base, col);
setPalette(pal);
pressed=true;
}
break;
case QEvent::MouseButtonRelease:
if (pressed && Qt::LeftButton==static_cast<QMouseEvent *>(event)->button() && !QApplication::overrideCursor()) {
actions().first()->trigger();
}
pressed=false;
break;
default:
break;
}
break;
case QEvent::MouseButtonRelease:
if (pressed && Qt::LeftButton==static_cast<QMouseEvent *>(event)->button() && !QApplication::overrideCursor()) {
actions().first()->trigger();
}
pressed=false;
break;
default:
break;
}
return QWidget::eventFilter(o, event);
}