Refactor more common stuff out of the library model, and add a simple last.fm service
This commit is contained in:
parent
9b2a5b1535
commit
9430a8fd2f
@ -1,5 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<qresource prefix="/">
|
||||
<file>clear.png</file>
|
||||
<file>go-home.png</file>
|
||||
<file>go-next.png</file>
|
||||
@ -33,5 +33,10 @@
|
||||
<file>exit.png</file>
|
||||
<file>copy.png</file>
|
||||
<file>move.png</file>
|
||||
<file>last.fm/as.png</file>
|
||||
<file>last.fm/loved_radio.png</file>
|
||||
<file>last.fm/neighbour_radio.png</file>
|
||||
<file>last.fm/personal_radio.png</file>
|
||||
<file>last.fm/recommended_radio.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
BIN
data/last.fm/as.png
Normal file
BIN
data/last.fm/as.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
BIN
data/last.fm/loved_radio.png
Normal file
BIN
data/last.fm/loved_radio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 936 B |
BIN
data/last.fm/neighbour_radio.png
Normal file
BIN
data/last.fm/neighbour_radio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 637 B |
BIN
data/last.fm/personal_radio.png
Normal file
BIN
data/last.fm/personal_radio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 580 B |
BIN
data/last.fm/recommended_radio.png
Normal file
BIN
data/last.fm/recommended_radio.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
36
src/lastfmservice.cpp
Normal file
36
src/lastfmservice.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "lastfmservice.h"
|
||||
#include "radioitem.h"
|
||||
|
||||
LastFMService::LastFMService(QObject* parent)
|
||||
: RadioService("Last.fm", parent)
|
||||
{
|
||||
}
|
||||
|
||||
RadioItem* LastFMService::CreateRootItem(RadioItem* parent) {
|
||||
RadioItem* item = new RadioItem(this, RadioItem::Type_Service, "Last.fm", parent);
|
||||
item->icon = QIcon(":last.fm/as.png");
|
||||
return item;
|
||||
}
|
||||
|
||||
void LastFMService::LazyPopulate(RadioItem *item) {
|
||||
switch (item->type) {
|
||||
case RadioItem::Type_Service:
|
||||
CreateStationItem(Type_MyRecommendations, "My Recommendations",
|
||||
":last.fm/recommended_radio.png", item);
|
||||
CreateStationItem(Type_MyRadio, "My Radio Station",
|
||||
":last.fm/personal_radio.png", item);
|
||||
CreateStationItem(Type_MyLoved, "My Loved Tracks",
|
||||
":last.fm/loved_radio.png", item);
|
||||
CreateStationItem(Type_MyNeighbourhood, "My Neighbourhood",
|
||||
":last.fm/neighbour_radio.png", item);
|
||||
}
|
||||
}
|
||||
|
||||
RadioItem* LastFMService::CreateStationItem(ItemType type, const QString& name,
|
||||
const QString& icon, RadioItem* parent) {
|
||||
RadioItem* ret = new RadioItem(this, type, name, parent);
|
||||
ret->lazy_loaded = true;
|
||||
ret->icon = QIcon(icon);
|
||||
|
||||
return ret;
|
||||
}
|
25
src/lastfmservice.h
Normal file
25
src/lastfmservice.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef LASTFMSERVICE_H
|
||||
#define LASTFMSERVICE_H
|
||||
|
||||
#include "radioservice.h"
|
||||
|
||||
class LastFMService : public RadioService {
|
||||
public:
|
||||
LastFMService(QObject* parent = 0);
|
||||
|
||||
enum ItemType {
|
||||
Type_MyRecommendations = 1000,
|
||||
Type_MyRadio,
|
||||
Type_MyLoved,
|
||||
Type_MyNeighbourhood,
|
||||
};
|
||||
|
||||
RadioItem* CreateRootItem(RadioItem* parent);
|
||||
void LazyPopulate(RadioItem *item);
|
||||
|
||||
private:
|
||||
RadioItem* CreateStationItem(ItemType type, const QString& name,
|
||||
const QString& icon, RadioItem* parent);
|
||||
};
|
||||
|
||||
#endif // LASTFMSERVICE_H
|
@ -11,11 +11,10 @@
|
||||
|
||||
|
||||
Library::Library(EngineBase* engine, QObject* parent)
|
||||
: QAbstractItemModel(parent),
|
||||
: SimpleTreeModel<LibraryItem>(new LibraryItem(LibraryItem::Type_Root), parent),
|
||||
engine_(engine),
|
||||
backend_(new BackgroundThread<LibraryBackend>(this)),
|
||||
watcher_(new BackgroundThread<LibraryWatcher>(this)),
|
||||
root_(new LibraryItem(LibraryItem::Type_Root)),
|
||||
artist_icon_(":artist.png"),
|
||||
album_icon_(":album.png"),
|
||||
config_(new LibraryConfig)
|
||||
@ -280,22 +279,6 @@ void Library::SongsDeleted(const SongList& songs) {
|
||||
}
|
||||
}
|
||||
|
||||
LibraryItem* Library::IndexToItem(const QModelIndex& index) const {
|
||||
if (!index.isValid())
|
||||
return root_;
|
||||
return reinterpret_cast<LibraryItem*>(index.internalPointer());
|
||||
}
|
||||
|
||||
QModelIndex Library::ItemToIndex(LibraryItem* item) const {
|
||||
if (!item || !item->parent)
|
||||
return QModelIndex();
|
||||
return createIndex(item->row, 0, item);
|
||||
}
|
||||
|
||||
int Library::columnCount(const QModelIndex &) const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant Library::data(const QModelIndex& index, int role) const {
|
||||
const LibraryItem* item = IndexToItem(index);
|
||||
|
||||
@ -334,33 +317,6 @@ QVariant Library::data(const LibraryItem* item, int role) const {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QModelIndex Library::index(int row, int, const QModelIndex& parent) const {
|
||||
LibraryItem* parent_item = IndexToItem(parent);
|
||||
if (!parent_item || parent_item->children.count() <= row)
|
||||
return QModelIndex();
|
||||
|
||||
return ItemToIndex(parent_item->children[row]);
|
||||
}
|
||||
|
||||
QModelIndex Library::parent(const QModelIndex& index) const {
|
||||
return ItemToIndex(IndexToItem(index)->parent);
|
||||
}
|
||||
|
||||
int Library::rowCount(const QModelIndex & parent) const {
|
||||
LibraryItem* item = IndexToItem(parent);
|
||||
const_cast<Library*>(this)->LazyPopulate(item); // Ahem
|
||||
|
||||
return item->children.count();
|
||||
}
|
||||
|
||||
bool Library::hasChildren(const QModelIndex &parent) const {
|
||||
LibraryItem* item = IndexToItem(parent);
|
||||
if (item->lazy_loaded)
|
||||
return !item->children.isEmpty();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void Library::LazyPopulate(LibraryItem* item) {
|
||||
if (item->lazy_loaded)
|
||||
return;
|
||||
|
@ -10,11 +10,12 @@
|
||||
#include "libraryquery.h"
|
||||
#include "engine_fwd.h"
|
||||
#include "song.h"
|
||||
#include "libraryitem.h"
|
||||
#include "simpletreemodel.h"
|
||||
|
||||
class LibraryItem;
|
||||
class LibraryConfig;
|
||||
|
||||
class Library : public QAbstractItemModel {
|
||||
class Library : public SimpleTreeModel<LibraryItem> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -34,12 +35,7 @@ class Library : public QAbstractItemModel {
|
||||
SongList GetChildSongs(const QModelIndex& index) const;
|
||||
|
||||
// QAbstractItemModel
|
||||
int columnCount(const QModelIndex & parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex & index) const;
|
||||
int rowCount(const QModelIndex & parent = QModelIndex()) const;
|
||||
bool hasChildren(const QModelIndex &parent) const;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||
QStringList mimeTypes() const;
|
||||
QMimeData* mimeData(const QModelIndexList& indexes) const;
|
||||
@ -54,6 +50,9 @@ class Library : public QAbstractItemModel {
|
||||
void SetFilterAge(int age);
|
||||
void SetFilterText(const QString& text);
|
||||
|
||||
protected:
|
||||
void LazyPopulate(LibraryItem* item);
|
||||
|
||||
private slots:
|
||||
// From LibraryBackend
|
||||
void BackendInitialised();
|
||||
@ -66,7 +65,6 @@ class Library : public QAbstractItemModel {
|
||||
|
||||
private:
|
||||
void Initialise();
|
||||
void LazyPopulate(LibraryItem* item);
|
||||
|
||||
LibraryItem* CreateCompilationArtistNode(bool signal);
|
||||
LibraryItem* CreateArtistNode(bool signal, const QString& name);
|
||||
@ -79,8 +77,6 @@ class Library : public QAbstractItemModel {
|
||||
QString SortTextForArtist(QString artist) const;
|
||||
QString SortTextForAlbum(QString album) const;
|
||||
|
||||
LibraryItem* IndexToItem(const QModelIndex& index) const;
|
||||
QModelIndex ItemToIndex(LibraryItem* item) const;
|
||||
QVariant data(const LibraryItem* item, int role) const;
|
||||
|
||||
bool CompareItems(const LibraryItem* a, const LibraryItem* b) const;
|
||||
@ -94,7 +90,6 @@ class Library : public QAbstractItemModel {
|
||||
|
||||
QueryOptions query_options_;
|
||||
|
||||
LibraryItem* root_;
|
||||
QMap<int, LibraryItem*> song_nodes_;
|
||||
QMap<QString, LibraryItem*> artist_nodes_;
|
||||
QMap<QChar, LibraryItem*> divider_nodes_;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "libraryconfig.h"
|
||||
#include "songplaylistitem.h"
|
||||
#include "systemtrayicon.h"
|
||||
#include "radiomodel.h"
|
||||
|
||||
#include <QFileSystemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
@ -25,6 +26,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
playlist_(new Playlist(this)),
|
||||
player_(new Player(playlist_, this)),
|
||||
library_(new Library(player_->GetEngine(), this)),
|
||||
radio_model_(new RadioModel(this)),
|
||||
library_sort_model_(new QSortFilterProxyModel(this)),
|
||||
tray_icon_(new SystemTrayIcon(this))
|
||||
{
|
||||
@ -47,6 +49,8 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
ui_.library_view->setModel(library_sort_model_);
|
||||
ui_.library_view->SetLibrary(library_);
|
||||
|
||||
ui_.radio_view->setModel(radio_model_);
|
||||
|
||||
// File view connections
|
||||
connect(ui_.file_view, SIGNAL(Queue(QList<QUrl>)), SLOT(QueueFiles(QList<QUrl>)));
|
||||
connect(ui_.file_view, SIGNAL(PathChanged(QString)), SLOT(FilePathChanged(QString)));
|
||||
|
@ -10,6 +10,7 @@ class Playlist;
|
||||
class Player;
|
||||
class Library;
|
||||
class LibraryConfig;
|
||||
class RadioModel;
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class SystemTrayIcon;
|
||||
@ -57,6 +58,7 @@ class MainWindow : public QMainWindow {
|
||||
Playlist* playlist_;
|
||||
Player* player_;
|
||||
Library* library_;
|
||||
RadioModel* radio_model_;
|
||||
|
||||
QSortFilterProxyModel* library_sort_model_;
|
||||
|
||||
|
@ -303,7 +303,41 @@
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>1</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_5"/>
|
||||
<widget class="QWidget" name="dockWidgetContents_5">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeView" name="radio_view">
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragOnly</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="files_dock">
|
||||
<property name="features">
|
||||
|
8
src/radioitem.cpp
Normal file
8
src/radioitem.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include "radioitem.h"
|
||||
|
||||
RadioItem::RadioItem(RadioService* _service, int type, const QString& key,
|
||||
RadioItem* parent)
|
||||
: SimpleTreeItem<RadioItem>(type, key, parent),
|
||||
service(_service)
|
||||
{
|
||||
}
|
24
src/radioitem.h
Normal file
24
src/radioitem.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef RADIOITEM_H
|
||||
#define RADIOITEM_H
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
#include "simpletreeitem.h"
|
||||
|
||||
class RadioService;
|
||||
|
||||
class RadioItem : public SimpleTreeItem<RadioItem> {
|
||||
public:
|
||||
enum Type {
|
||||
Type_Root = 1,
|
||||
Type_Service,
|
||||
};
|
||||
|
||||
RadioItem(RadioService* _service, int type, const QString& key = QString::null,
|
||||
RadioItem* parent = NULL);
|
||||
|
||||
QIcon icon;
|
||||
RadioService* service;
|
||||
};
|
||||
|
||||
#endif // RADIOITEM_H
|
45
src/radiomodel.cpp
Normal file
45
src/radiomodel.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "radiomodel.h"
|
||||
#include "radioservice.h"
|
||||
#include "lastfmservice.h"
|
||||
|
||||
RadioModel::RadioModel(QObject* parent)
|
||||
: SimpleTreeModel<RadioItem>(new RadioItem(NULL, RadioItem::Type_Root), parent)
|
||||
{
|
||||
root_->lazy_loaded = true;
|
||||
|
||||
LastFMService* lastfm = new LastFMService(this);
|
||||
services_ << lastfm;
|
||||
lastfm->CreateRootItem(root_);
|
||||
}
|
||||
|
||||
QVariant RadioModel::data(const QModelIndex& index, int role) const {
|
||||
const RadioItem* item = IndexToItem(index);
|
||||
|
||||
return data(item, role);
|
||||
}
|
||||
|
||||
QVariant RadioModel::data(const RadioItem* item, int role) const {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return item->DisplayText();
|
||||
|
||||
case Qt::DecorationRole:
|
||||
return item->icon;
|
||||
break;
|
||||
|
||||
case Role_Type:
|
||||
return item->type;
|
||||
|
||||
case Role_Key:
|
||||
return item->key;
|
||||
|
||||
case Role_SortText:
|
||||
return item->SortText();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void RadioModel::LazyPopulate(RadioItem* parent) {
|
||||
if (parent->service)
|
||||
parent->service->LazyPopulate(parent);
|
||||
}
|
32
src/radiomodel.h
Normal file
32
src/radiomodel.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef RADIOMODEL_H
|
||||
#define RADIOMODEL_H
|
||||
|
||||
#include "radioitem.h"
|
||||
#include "simpletreemodel.h"
|
||||
|
||||
class RadioService;
|
||||
|
||||
class RadioModel : public SimpleTreeModel<RadioItem> {
|
||||
public:
|
||||
RadioModel(QObject* parent = 0);
|
||||
|
||||
enum {
|
||||
Role_Type = Qt::UserRole + 1,
|
||||
Role_SortText,
|
||||
Role_Key,
|
||||
};
|
||||
|
||||
// QAbstractItemModel
|
||||
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
|
||||
protected:
|
||||
void LazyPopulate(RadioItem* parent);
|
||||
|
||||
private:
|
||||
QVariant data(const RadioItem* item, int role) const;
|
||||
|
||||
private:
|
||||
QList<RadioService*> services_;
|
||||
};
|
||||
|
||||
#endif // RADIOMODEL_H
|
7
src/radioservice.cpp
Normal file
7
src/radioservice.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "radioservice.h"
|
||||
|
||||
RadioService::RadioService(const QString& name, QObject *parent)
|
||||
: QObject(parent),
|
||||
name_(name)
|
||||
{
|
||||
}
|
23
src/radioservice.h
Normal file
23
src/radioservice.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef RADIOSERVICE_H
|
||||
#define RADIOSERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class RadioItem;
|
||||
|
||||
class RadioService : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RadioService(const QString& name, QObject* parent = 0);
|
||||
|
||||
QString name() const { return name_; }
|
||||
|
||||
virtual RadioItem* CreateRootItem(RadioItem* parent) = 0;
|
||||
virtual void LazyPopulate(RadioItem* item) = 0;
|
||||
|
||||
private:
|
||||
QString name_;
|
||||
};
|
||||
|
||||
#endif // RADIOSERVICE_H
|
89
src/simpletreemodel.h
Normal file
89
src/simpletreemodel.h
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef SIMPLETREEMODEL_H
|
||||
#define SIMPLETREEMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
template <typename T>
|
||||
class SimpleTreeModel : public QAbstractItemModel {
|
||||
public:
|
||||
SimpleTreeModel(T* root = 0, QObject* parent = 0);
|
||||
virtual ~SimpleTreeModel() {}
|
||||
|
||||
// QAbstractItemModel
|
||||
int columnCount(const QModelIndex& parent) const;
|
||||
QModelIndex index(int row, int, const QModelIndex& parent) const;
|
||||
QModelIndex parent(const QModelIndex& index) const;
|
||||
int rowCount(const QModelIndex& parent) const;
|
||||
bool hasChildren(const QModelIndex& parent) const;
|
||||
|
||||
protected:
|
||||
T* IndexToItem(const QModelIndex& index) const;
|
||||
QModelIndex ItemToIndex(T* item) const;
|
||||
|
||||
virtual void LazyPopulate(T* item) = 0;
|
||||
|
||||
protected:
|
||||
T* root_;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
SimpleTreeModel<T>::SimpleTreeModel(T* root, QObject* parent)
|
||||
: QAbstractItemModel(parent),
|
||||
root_(root)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* SimpleTreeModel<T>::IndexToItem(const QModelIndex& index) const {
|
||||
if (!index.isValid())
|
||||
return root_;
|
||||
return reinterpret_cast<T*>(index.internalPointer());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QModelIndex SimpleTreeModel<T>::ItemToIndex(T* item) const {
|
||||
if (!item || !item->parent)
|
||||
return QModelIndex();
|
||||
return createIndex(item->row, 0, item);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int SimpleTreeModel<T>::columnCount(const QModelIndex &) const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QModelIndex SimpleTreeModel<T>::index(int row, int, const QModelIndex& parent) const {
|
||||
T* parent_item = IndexToItem(parent);
|
||||
if (!parent_item || parent_item->children.count() <= row)
|
||||
return QModelIndex();
|
||||
|
||||
return ItemToIndex(parent_item->children[row]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QModelIndex SimpleTreeModel<T>::parent(const QModelIndex& index) const {
|
||||
return ItemToIndex(IndexToItem(index)->parent);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int SimpleTreeModel<T>::rowCount(const QModelIndex & parent) const {
|
||||
T* item = IndexToItem(parent);
|
||||
const_cast<SimpleTreeModel<T>*>(this)->LazyPopulate(item); // Ahem
|
||||
|
||||
return item->children.count();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SimpleTreeModel<T>::hasChildren(const QModelIndex &parent) const {
|
||||
T* item = IndexToItem(parent);
|
||||
if (item->lazy_loaded)
|
||||
return !item->children.isEmpty();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // SIMPLETREEMODEL_H
|
13
src/src.pro
13
src/src.pro
@ -32,7 +32,11 @@ SOURCES += main.cpp \
|
||||
libraryquery.cpp \
|
||||
fileview.cpp \
|
||||
fileviewlist.cpp \
|
||||
playlistheader.cpp
|
||||
playlistheader.cpp \
|
||||
radioitem.cpp \
|
||||
radioservice.cpp \
|
||||
lastfmservice.cpp \
|
||||
radiomodel.cpp
|
||||
HEADERS += mainwindow.h \
|
||||
player.h \
|
||||
library.h \
|
||||
@ -63,7 +67,12 @@ HEADERS += mainwindow.h \
|
||||
fileview.h \
|
||||
fileviewlist.h \
|
||||
playlistheader.h \
|
||||
simpletreeitem.h
|
||||
simpletreeitem.h \
|
||||
radioitem.h \
|
||||
radioservice.h \
|
||||
lastfmservice.h \
|
||||
simpletreemodel.h \
|
||||
radiomodel.h
|
||||
FORMS += mainwindow.ui \
|
||||
libraryconfig.ui \
|
||||
fileview.ui
|
||||
|
Loading…
x
Reference in New Issue
Block a user