Refactor more common stuff out of the library model, and add a simple last.fm service

This commit is contained in:
David Sansome 2009-12-26 15:13:38 +00:00
parent 9b2a5b1535
commit 9430a8fd2f
21 changed files with 354 additions and 60 deletions

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

36
src/lastfmservice.cpp Normal file
View 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
View 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

View File

@ -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;

View File

@ -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_;

View File

@ -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)));

View File

@ -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_;

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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