Cache certain stream listings
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include "thread.h"
|
||||
#include "settings.h"
|
||||
#include "treeview.h"
|
||||
#include "streamsmodel.h"
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStyle>
|
||||
@@ -241,6 +242,7 @@ CacheSettings::CacheSettings(QWidget *parent)
|
||||
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);
|
||||
#ifdef ENABLE_ONLINE_SERVICES
|
||||
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);
|
||||
|
||||
@@ -70,7 +70,9 @@ StreamsModel * StreamsModel::self()
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString StreamsModel::constPrefix("cantata-");
|
||||
const QString StreamsModel::constPrefix=QLatin1String("cantata-");
|
||||
const QString StreamsModel::constCacheDir=QLatin1String("streams");
|
||||
const QString StreamsModel::constCacheExt=QLatin1String(".xml.gz");
|
||||
|
||||
static const char * constOrigUrlProperty = "orig-url";
|
||||
|
||||
@@ -124,6 +126,11 @@ static QIcon getIcon(const QString &name)
|
||||
return Icons::self()->streamCategoryIcon;
|
||||
}
|
||||
|
||||
static QString cacheName(const QString &name, bool createDir=false)
|
||||
{
|
||||
return Utils::cacheDir(StreamsModel::constCacheDir, createDir)+name+StreamsModel::constCacheExt;
|
||||
}
|
||||
|
||||
StreamsModel::StreamsModel(QObject *parent)
|
||||
: ActionModel(parent)
|
||||
, root(new CategoryItem(QString(), "root"))
|
||||
@@ -132,13 +139,13 @@ StreamsModel::StreamsModel(QObject *parent)
|
||||
, favouritesSaveTimer(0)
|
||||
{
|
||||
root->children.append(new CategoryItem(constRadioTimeUrl+QLatin1String("?locale=")+QLocale::system().name(), i18n("TuneIn"), root, getIcon("tunein")));
|
||||
root->children.append(new CategoryItem(constIceCastUrl, i18n("IceCast"), root, getIcon("icecast")));
|
||||
root->children.append(new CategoryItem(constIceCastUrl, i18n("IceCast"), root, getIcon("icecast"), "icecast"));
|
||||
root->children.append(new CategoryItem(constShoutCastUrl, i18n("ShoutCast"), root, getIcon("shoutcast")));
|
||||
root->children.append(new CategoryItem(constSomaFMUrl, i18n("SomaFM"), root, getIcon("somafm")));
|
||||
root->children.append(new CategoryItem(constDigitallyImportedUrl, i18n("Digitally Imported"), root, getIcon("digitallyimported")));
|
||||
root->children.append(new CategoryItem(constJazzRadioUrl, i18n("JazzRadio.com"), root, getIcon("jazzradio")));
|
||||
root->children.append(new CategoryItem(constRockRadioUrl, i18n("RockRadio.com"), root, getIcon("rockradio")));
|
||||
root->children.append(new CategoryItem(constSkyFmUrl, i18n("Sky.fm"), root, getIcon("skyfm")));
|
||||
root->children.append(new CategoryItem(constSomaFMUrl, i18n("SomaFM"), root, getIcon("somafm"), "somafm"));
|
||||
root->children.append(new CategoryItem(constDigitallyImportedUrl, i18n("Digitally Imported"), root, getIcon("digitallyimported"), "di"));
|
||||
root->children.append(new CategoryItem(constJazzRadioUrl, i18n("JazzRadio.com"), root, getIcon("jazzradio"), "jazzradio"));
|
||||
root->children.append(new CategoryItem(constRockRadioUrl, i18n("RockRadio.com"), root, getIcon("rockradio"), "rockradio"));
|
||||
root->children.append(new CategoryItem(constSkyFmUrl, i18n("Sky.fm"), root, getIcon("skyfm"), "skyfm"));
|
||||
favourites=new CategoryItem(constFavouritesUrl, i18n("Favourites"), root, getIcon("favourites"));
|
||||
favourites->isFavourites=true;
|
||||
root->children.append(favourites);
|
||||
@@ -280,7 +287,7 @@ void StreamsModel::fetchMore(const QModelIndex &index)
|
||||
emit dataChanged(index, index);
|
||||
loadFavourites(index);
|
||||
cat->state=CategoryItem::Fetched;
|
||||
} else {
|
||||
} else if (!loadCache(cat)) {
|
||||
QNetworkRequest req;
|
||||
if (constDiUrls.contains(cat->url)) {
|
||||
req=QNetworkRequest(constDiChannelListUrl.arg(cat->url.split(".").at(1)));
|
||||
@@ -292,13 +299,6 @@ void StreamsModel::fetchMore(const QModelIndex &index)
|
||||
req=QNetworkRequest(cat->url);
|
||||
}
|
||||
|
||||
if (cat==favourites && !favourites->children.isEmpty()) {
|
||||
beginRemoveRows(index, 0, favourites->children.count()-1);
|
||||
qDeleteAll(favourites->children);
|
||||
favourites->children.clear();
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
QNetworkReply *job=NetworkAccessManager::self()->get(req);
|
||||
job->setProperty(constOrigUrlProperty, cat->url);
|
||||
if (jobs.isEmpty()) {
|
||||
@@ -349,7 +349,30 @@ bool StreamsModel::checkFavouritesWritable()
|
||||
|
||||
void StreamsModel::reloadFavourites()
|
||||
{
|
||||
fetchMore(createIndex(root->children.indexOf(favourites), 0, favourites));
|
||||
reload(createIndex(root->children.indexOf(favourites), 0, favourites));
|
||||
}
|
||||
|
||||
void StreamsModel::reload(const QModelIndex &index)
|
||||
{
|
||||
Item *item = toItem(index);
|
||||
if (!item->isCategory()) {
|
||||
return;
|
||||
}
|
||||
CategoryItem *cat=static_cast<CategoryItem *>(item);
|
||||
if (!cat->children.isEmpty()) {
|
||||
beginRemoveRows(index, 0, cat->children.count()-1);
|
||||
qDeleteAll(cat->children);
|
||||
cat->children.clear();
|
||||
endRemoveRows();
|
||||
if (!cat->cacheName.isEmpty()) {
|
||||
QString cache=cacheName(cat->cacheName);
|
||||
if (QFile::exists(cache)) {
|
||||
QFile::remove(cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchMore(index);
|
||||
}
|
||||
|
||||
void StreamsModel::removeFromFavourites(const QModelIndex &index)
|
||||
@@ -432,16 +455,16 @@ bool StreamsModel::importXml(const QString &fileName)
|
||||
return loadXml(fileName, createIndex(root->children.indexOf(favourites), 0, favourites));
|
||||
}
|
||||
|
||||
bool StreamsModel::saveXml(const QString &fileName, const QList<Item *> &items)
|
||||
bool StreamsModel::saveXml(const QString &fileName, const QList<Item *> &items, bool format)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
||||
if (fileName.endsWith(".xml")) {
|
||||
return file.open(QIODevice::WriteOnly) && saveXml(&file, items.isEmpty() ? favourites->children : items, true);
|
||||
return file.open(QIODevice::WriteOnly) && saveXml(&file, items.isEmpty() ? favourites->children : items, format);
|
||||
} else {
|
||||
QtIOCompressor compressor(&file);
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
return compressor.open(QIODevice::WriteOnly) && saveXml(&compressor, items.isEmpty() ? favourites->children : items, false);
|
||||
return compressor.open(QIODevice::WriteOnly) && saveXml(&compressor, items.isEmpty() ? favourites->children : items, format);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,6 +526,34 @@ QStringList StreamsModel::mimeTypes() const
|
||||
return types;
|
||||
}
|
||||
|
||||
bool StreamsModel::loadCache(CategoryItem *cat)
|
||||
{
|
||||
if (!cat->cacheName.isEmpty()) {
|
||||
QString cache=cacheName(cat->cacheName);
|
||||
if (!cache.isEmpty()) {
|
||||
QList<Item *> newItems=loadXml(cache, cat, false);
|
||||
if (!newItems.isEmpty()) {
|
||||
QModelIndex index=createIndex(cat->parent->children.indexOf(cat), 0, (void *)cat);
|
||||
beginInsertRows(index, cat->children.count(), (cat->children.count()+newItems.count())-1);
|
||||
cat->children+=newItems;
|
||||
endInsertRows();
|
||||
cat->state=CategoryItem::Fetched;
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StreamsModel::saveCache(CategoryItem *cat, const QList<Item *> &items)
|
||||
{
|
||||
if (!cat->cacheName.isEmpty()) {
|
||||
saveXml(cacheName(cat->cacheName, true), items, false);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamsModel::jobFinished()
|
||||
{
|
||||
QNetworkReply *job=dynamic_cast<QNetworkReply *>(sender());
|
||||
@@ -522,7 +573,7 @@ void StreamsModel::jobFinished()
|
||||
if (QNetworkReply::NoError==job->error()) {
|
||||
QList<Item *> newItems;
|
||||
if (cat==favourites) {
|
||||
newItems=loadXml(job, true);
|
||||
newItems=loadXml(job, cat, true);
|
||||
} else if (QLatin1String("http")==job->url().scheme()) {
|
||||
QString url=job->url().toString();
|
||||
if (constRadioTimeHost==job->url().host()) {
|
||||
@@ -532,12 +583,13 @@ void StreamsModel::jobFinished()
|
||||
} else if (constSomaFMUrl==url) {
|
||||
newItems=parseSomaFmResponse(job, cat);
|
||||
} else if (constDiChannelListHost==job->url().host()) {
|
||||
newItems=parseDigitallyImportedResponse(job, cat, job->property(constOrigUrlProperty).toString());
|
||||
newItems=parseDigitallyImportedResponse(job, cat);
|
||||
} else if (constShoutCastHost==job->url().host()) {
|
||||
newItems=parseShoutCastResponse(job, cat, job->property(constOrigUrlProperty).toString());
|
||||
} else {
|
||||
newItems=parseListenLiveResponse(job, cat);
|
||||
}
|
||||
saveCache(cat, newItems);
|
||||
}
|
||||
|
||||
if (!newItems.isEmpty()) {
|
||||
@@ -777,12 +829,12 @@ QList<StreamsModel::Item *> StreamsModel::parseSomaFmResponse(QIODevice *dev, Ca
|
||||
return newItems;
|
||||
}
|
||||
|
||||
QList<StreamsModel::Item *> StreamsModel::parseDigitallyImportedResponse(QIODevice *dev, CategoryItem *cat, const QString &origUrl)
|
||||
QList<StreamsModel::Item *> StreamsModel::parseDigitallyImportedResponse(QIODevice *dev, CategoryItem *cat)
|
||||
{
|
||||
QList<Item *> newItems;
|
||||
QJson::Parser parser;
|
||||
QVariantMap data = parser.parse(dev).toMap();
|
||||
QString listenHost=QLatin1String("listen.")+QUrl(origUrl).host().remove("www.");
|
||||
QString listenHost=QLatin1String("listen.")+QUrl(cat->url).host().remove("www.");
|
||||
|
||||
if (data.contains("channel_filters")) {
|
||||
QVariantList filters = data["channel_filters"].toList();
|
||||
@@ -1131,24 +1183,7 @@ void StreamsModel::loadFavourites(const QModelIndex &index)
|
||||
|
||||
bool StreamsModel::loadXml(const QString &fileName, const QModelIndex &index)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
// Check for gzip header...
|
||||
QByteArray header=file.read(2);
|
||||
bool isCompressed=((unsigned char)header[0])==0x1f && ((unsigned char)header[1])==0x8b;
|
||||
file.seek(0);
|
||||
|
||||
QtIOCompressor compressor(&file);
|
||||
if (isCompressed) {
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (!compressor.open(QIODevice::ReadOnly)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QList<Item *> newItems=loadXml(isCompressed ? (QIODevice *)&compressor : (QIODevice *)&file, true);
|
||||
QList<Item *> newItems=loadXml(fileName, favourites, true);
|
||||
|
||||
if (!newItems.isEmpty()) {
|
||||
beginInsertRows(index, favourites->children.count(), (favourites->children.count()+newItems.count())-1);
|
||||
@@ -1159,47 +1194,120 @@ bool StreamsModel::loadXml(const QString &fileName, const QModelIndex &index)
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<StreamsModel::Item *> StreamsModel::loadXml(QIODevice *dev, bool isInternal)
|
||||
QList<StreamsModel::Item *> StreamsModel::loadXml(const QString &fileName, CategoryItem *cat, bool isInternal)
|
||||
{
|
||||
QList<Item *> newItems;
|
||||
QXmlStreamReader doc(dev);
|
||||
QSet<QString> existingUrls;
|
||||
QSet<QString> existingNames;
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
return QList<StreamsModel::Item *>();
|
||||
}
|
||||
// Check for gzip header...
|
||||
QByteArray header=file.read(2);
|
||||
bool isCompressed=((unsigned char)header[0])==0x1f && ((unsigned char)header[1])==0x8b;
|
||||
file.seek(0);
|
||||
|
||||
if (!isInternal) {
|
||||
foreach (Item *i, favourites->children) {
|
||||
existingUrls.insert(i->url);
|
||||
existingNames.insert(i->name);
|
||||
QtIOCompressor compressor(&file);
|
||||
if (isCompressed) {
|
||||
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||
if (!compressor.open(QIODevice::ReadOnly)) {
|
||||
return QList<StreamsModel::Item *>();
|
||||
}
|
||||
}
|
||||
|
||||
while (!doc.atEnd()) {
|
||||
doc.readNext();
|
||||
return loadXml(isCompressed ? (QIODevice *)&compressor : (QIODevice *)&file, cat, isInternal);
|
||||
}
|
||||
|
||||
if (doc.isStartElement() && QLatin1String("stream")==doc.name()) {
|
||||
QString name=doc.attributes().value("name").toString();
|
||||
QString origName=name;
|
||||
QString url=doc.attributes().value("url").toString();
|
||||
QList<StreamsModel::Item *> StreamsModel::loadXml(QIODevice *dev, CategoryItem *cat, bool isInternal)
|
||||
{
|
||||
QList<Item *> newItems;
|
||||
QXmlStreamReader doc(dev);
|
||||
|
||||
if (!name.isEmpty() && !name.isEmpty() && (isInternal || !existingUrls.contains(url))) {
|
||||
int i=1;
|
||||
if (!isInternal) {
|
||||
for (; i<100 && existingNames.contains(name); ++i) {
|
||||
name=origName+QLatin1String("_")+QString::number(i);
|
||||
if (cat==favourites) {
|
||||
QSet<QString> existingUrls;
|
||||
QSet<QString> existingNames;
|
||||
|
||||
if (!isInternal) {
|
||||
foreach (Item *i, favourites->children) {
|
||||
existingUrls.insert(i->url);
|
||||
existingNames.insert(i->name);
|
||||
}
|
||||
}
|
||||
|
||||
while (!doc.atEnd()) {
|
||||
doc.readNext();
|
||||
|
||||
if (doc.isStartElement() && QLatin1String("stream")==doc.name()) {
|
||||
QString name=doc.attributes().value("name").toString();
|
||||
QString origName=name;
|
||||
QString url=doc.attributes().value("url").toString();
|
||||
|
||||
if (!name.isEmpty() && !name.isEmpty() && (isInternal || !existingUrls.contains(url))) {
|
||||
int i=1;
|
||||
if (!isInternal) {
|
||||
for (; i<100 && existingNames.contains(name); ++i) {
|
||||
name=origName+QLatin1String("_")+QString::number(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (i<100) {
|
||||
existingNames.insert(name);
|
||||
existingUrls.insert(url);
|
||||
newItems.append(new Item(url, name, cat));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CategoryItem *currentCat=cat;
|
||||
CategoryItem *prevCat=cat;
|
||||
while (!doc.atEnd()) {
|
||||
doc.readNext();
|
||||
|
||||
if (i<100) {
|
||||
existingNames.insert(name);
|
||||
existingUrls.insert(url);
|
||||
newItems.append(new Item(url, name, favourites));
|
||||
if (doc.isStartElement()) {
|
||||
if (QLatin1String("stream")==doc.name()) {
|
||||
QString name=doc.attributes().value("name").toString();
|
||||
QString url=doc.attributes().value("url").toString();
|
||||
if (currentCat==cat) {
|
||||
newItems.append(new Item(url, name, currentCat));
|
||||
} else {
|
||||
currentCat->children.append(new Item(url, name, currentCat));
|
||||
}
|
||||
} else if (QLatin1String("category")==doc.name()) {
|
||||
prevCat=currentCat;
|
||||
QString name=doc.attributes().value("name").toString();
|
||||
currentCat=new CategoryItem(QString(), name, prevCat);
|
||||
currentCat->state=CategoryItem::Fetched;
|
||||
newItems.append(currentCat);
|
||||
}
|
||||
} if (doc.isEndElement() && QLatin1String("category")==doc.name()) {
|
||||
currentCat=prevCat;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newItems;
|
||||
}
|
||||
|
||||
static void saveStream(QXmlStreamWriter &doc, const StreamsModel::Item *item)
|
||||
{
|
||||
doc.writeStartElement("stream");
|
||||
doc.writeAttribute("name", item->name);
|
||||
doc.writeAttribute("url", item->url);
|
||||
doc.writeEndElement();
|
||||
}
|
||||
|
||||
static void saveCategory(QXmlStreamWriter &doc, const StreamsModel::CategoryItem *cat)
|
||||
{
|
||||
doc.writeStartElement("category");
|
||||
doc.writeAttribute("name", cat->name);
|
||||
foreach (const StreamsModel::Item *i, cat->children) {
|
||||
if (i->isCategory()) {
|
||||
saveCategory(doc, static_cast<const StreamsModel::CategoryItem *>(i));
|
||||
} else {
|
||||
saveStream(doc, static_cast<const StreamsModel::Item *>(i));
|
||||
}
|
||||
}
|
||||
doc.writeEndElement();
|
||||
}
|
||||
|
||||
bool StreamsModel::saveXml(QIODevice *dev, const QList<Item *> &items, bool format) const
|
||||
{
|
||||
QXmlStreamWriter doc(dev);
|
||||
@@ -1214,10 +1322,11 @@ bool StreamsModel::saveXml(QIODevice *dev, const QList<Item *> &items, bool form
|
||||
}
|
||||
|
||||
foreach (const Item *i, items) {
|
||||
doc.writeStartElement("stream");
|
||||
doc.writeAttribute("name", i->name);
|
||||
doc.writeAttribute("url", i->url);
|
||||
doc.writeEndElement();
|
||||
if (i->isCategory()) {
|
||||
saveCategory(doc, static_cast<const CategoryItem *>(i));
|
||||
} else {
|
||||
saveStream(doc, i);
|
||||
}
|
||||
}
|
||||
doc.writeEndElement();
|
||||
doc.writeEndDocument();
|
||||
@@ -1238,9 +1347,20 @@ void StreamsModel::buildListenLive()
|
||||
doc.readNext();
|
||||
if (doc.isStartElement()) {
|
||||
if (QLatin1String("listing")==doc.name()) {
|
||||
region->children.append(new CategoryItem(doc.attributes().value("url").toString(),
|
||||
QString url=doc.attributes().value("url").toString();
|
||||
QString cache=doc.attributes().value("cache").toString();
|
||||
if (cache.isEmpty() && url.endsWith(".html")) {
|
||||
QStringList parts=url.split("/", QString::SkipEmptyParts);
|
||||
if (!parts.isEmpty()) {
|
||||
cache=parts.last().remove((".html"));
|
||||
}
|
||||
}
|
||||
if (!cache.isEmpty()) {
|
||||
cache="ll-"+cache;
|
||||
}
|
||||
region->children.append(new CategoryItem(url,
|
||||
doc.attributes().value("name").toString(),
|
||||
region));
|
||||
region, QIcon(), cache));
|
||||
} else if (QLatin1String("region")==doc.name()) {
|
||||
prevRegion=region;
|
||||
region=new CategoryItem(QString(), doc.attributes().value("name").toString(), prevRegion);
|
||||
|
||||
@@ -60,8 +60,8 @@ public:
|
||||
Fetched
|
||||
};
|
||||
|
||||
CategoryItem(const QString &u, const QString &n=QString(), CategoryItem *p=0, const QIcon &i=QIcon())
|
||||
: Item(u, n, p), state(Initial), isFavourites(false), isAll(false), icon(i) { }
|
||||
CategoryItem(const QString &u, const QString &n=QString(), CategoryItem *p=0, const QIcon &i=QIcon(), const QString &cn=QString())
|
||||
: Item(u, n, p), state(Initial), isFavourites(false), isAll(false), icon(i), cacheName(cn) { }
|
||||
virtual ~CategoryItem() { qDeleteAll(children); }
|
||||
virtual bool isCategory() const { return true; }
|
||||
State state;
|
||||
@@ -69,9 +69,12 @@ public:
|
||||
bool isAll : 1;
|
||||
QList<Item *> children;
|
||||
QIcon icon;
|
||||
QString cacheName;
|
||||
};
|
||||
|
||||
|
||||
static const QString constPrefix;
|
||||
static const QString constCacheDir;
|
||||
static const QString constCacheExt;
|
||||
|
||||
static StreamsModel * self();
|
||||
static QString favouritesDir();
|
||||
@@ -96,6 +99,7 @@ public:
|
||||
bool isFavoritesWritable() { return favouritesIsWriteable; }
|
||||
bool checkFavouritesWritable();
|
||||
void reloadFavourites();
|
||||
void reload(const QModelIndex &index);
|
||||
void removeFromFavourites(const QModelIndex &index);
|
||||
void addToFavourites(const QString &url, const QString &name);
|
||||
QString favouritesNameForUrl(const QString &u);
|
||||
@@ -103,12 +107,14 @@ public:
|
||||
void updateFavouriteStream(Item *item);
|
||||
|
||||
bool importXml(const QString &fileName);
|
||||
bool saveXml(const QString &fileName, const QList<Item *> &items);
|
||||
bool saveXml(const QString &fileName, const QList<Item *> &items, bool format=true);
|
||||
|
||||
QStringList filenames(const QModelIndexList &indexes, bool addPrefix) const;
|
||||
QMimeData * mimeData(const QModelIndexList &indexes) const;
|
||||
QStringList mimeTypes() const;
|
||||
|
||||
bool isTopLevel(const CategoryItem *cat) const { return cat && root==cat->parent; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void loading();
|
||||
void loaded();
|
||||
@@ -119,11 +125,13 @@ private Q_SLOTS:
|
||||
void persistFavourites();
|
||||
|
||||
private:
|
||||
bool loadCache(CategoryItem *cat);
|
||||
void saveCache(CategoryItem *cat, const QList<Item *> &items);
|
||||
Item * toItem(const QModelIndex &index) const { return index.isValid() ? static_cast<Item*>(index.internalPointer()) : root; }
|
||||
QList<Item *> parseRadioTimeResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseIceCastResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseSomaFmResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseDigitallyImportedResponse(QIODevice *dev, CategoryItem *cat, const QString &origUrl);
|
||||
QList<Item *> parseDigitallyImportedResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseListenLiveResponse(QIODevice *dev, CategoryItem *cat);
|
||||
QList<Item *> parseShoutCastResponse(QIODevice *dev, CategoryItem *cat, const QString &origUrl);
|
||||
QList<Item *> parseShoutCastLinks(QXmlStreamReader &doc, CategoryItem *cat);
|
||||
@@ -132,7 +140,8 @@ private:
|
||||
Item * parseSomaFmEntry(QXmlStreamReader &doc, CategoryItem *parent);
|
||||
void loadFavourites(const QModelIndex &index);
|
||||
bool loadXml(const QString &fileName, const QModelIndex &index);
|
||||
QList<Item *> loadXml(QIODevice *dev, bool isInternal);
|
||||
QList<Item *> loadXml(const QString &fileName, CategoryItem *cat, bool isInternal);
|
||||
QList<Item *> loadXml(QIODevice *dev, CategoryItem *cat, bool isInternal);
|
||||
bool saveXml(QIODevice *dev, const QList<Item *> &items, bool format) const;
|
||||
void buildListenLive();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<streams>
|
||||
<listing name="Australia" url="http://www.australianliveradio.com/"/>
|
||||
<listing name="Australia" url="http://www.australianliveradio.com/" cache="australia"/>
|
||||
<region name="Europe">
|
||||
<listing name="Albania" url="http://www.listenlive.eu/albania.html"/>
|
||||
<listing name="Andorra" url="http://www.listenlive.eu/andorra.html"/>
|
||||
@@ -69,6 +69,6 @@
|
||||
<listing name="Saskatchewan" url="http://www.canadianwebradio.com/saskatchewan.html"/>
|
||||
<listing name="Yukon" url="http://www.canadianwebradio.com/yukon.html"/>
|
||||
</region>
|
||||
<listing name="New Zealand" url="http://www.nzradioguide.co.nz/"/>
|
||||
<listing name="USA" url="http://www.usliveradio.com/"/>
|
||||
<listing name="New Zealand" url="http://www.nzradioguide.co.nz/" cache="newzealand"/>
|
||||
<listing name="USA" url="http://www.usliveradio.com/" cache="usa"/>
|
||||
</streams>
|
||||
|
||||
@@ -56,6 +56,7 @@ StreamsPage::StreamsPage(QWidget *p)
|
||||
exportAction = ActionCollection::get()->createAction("exportstreams", i18n("Export Favourite Streams"), "document-export");
|
||||
addAction = ActionCollection::get()->createAction("addstream", i18n("Add New Stream To Favourites"), Icons::self()->addRadioStreamIcon);
|
||||
addToFavouritesAction = ActionCollection::get()->createAction("addtofavourites", i18n("Add Stream To Favourites"), Icons::self()->addRadioStreamIcon);
|
||||
reloadAction = ActionCollection::get()->createAction("reloadstreams", i18n("Reload"), Icon("view-refresh"));
|
||||
editAction = ActionCollection::get()->createAction("editstream", i18n("Edit"), Icons::self()->editIcon);
|
||||
Action *settingsAct = new Action(i18n("Digitally Imported Settings"), this);
|
||||
replacePlayQueue->setDefaultAction(StdActions::self()->replacePlayQueueAction);
|
||||
@@ -65,6 +66,7 @@ StreamsPage::StreamsPage(QWidget *p)
|
||||
connect(view, SIGNAL(itemsSelected(bool)), SLOT(controlActions()));
|
||||
connect(addAction, SIGNAL(triggered(bool)), this, SLOT(add()));
|
||||
connect(addToFavouritesAction, SIGNAL(triggered(bool)), this, SLOT(addToFavourites()));
|
||||
connect(reloadAction, SIGNAL(triggered(bool)), this, SLOT(reload()));
|
||||
connect(editAction, SIGNAL(triggered(bool)), this, SLOT(edit()));
|
||||
connect(importAction, SIGNAL(triggered(bool)), this, SLOT(importXml()));
|
||||
connect(exportAction, SIGNAL(triggered(bool)), this, SLOT(exportXml()));
|
||||
@@ -78,6 +80,7 @@ StreamsPage::StreamsPage(QWidget *p)
|
||||
menu->addAction(addAction);
|
||||
menu->addAction(StdActions::self()->removeAction);
|
||||
menu->addAction(editAction);
|
||||
menu->addAction(reloadAction);
|
||||
menu->addSeparator();
|
||||
menu->addAction(importAction);
|
||||
menu->addAction(exportAction);
|
||||
@@ -95,6 +98,7 @@ StreamsPage::StreamsPage(QWidget *p)
|
||||
view->addAction(editAction);
|
||||
view->addAction(StdActions::self()->removeAction);
|
||||
view->addAction(addToFavouritesAction);
|
||||
view->addAction(reloadAction);
|
||||
proxy.setSourceModel(StreamsModel::self());
|
||||
view->setModel(&proxy);
|
||||
view->setDeleteAction(StdActions::self()->removeAction);
|
||||
@@ -285,6 +289,27 @@ void StreamsPage::addToFavourites()
|
||||
}
|
||||
}
|
||||
|
||||
void StreamsPage::reload()
|
||||
{
|
||||
QModelIndexList selected = view->selectedIndexes();
|
||||
if (1!=selected.count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex mapped=proxy.mapToSource(selected.first());
|
||||
const StreamsModel::Item *item=static_cast<const StreamsModel::Item *>(mapped.internalPointer());
|
||||
if (!item->isCategory()) {
|
||||
return;
|
||||
}
|
||||
const StreamsModel::CategoryItem *cat=static_cast<const StreamsModel::CategoryItem *>(item);
|
||||
if (!StreamsModel::self()->isTopLevel(cat)) {
|
||||
return;
|
||||
}
|
||||
if (cat->children.isEmpty() || MessageBox::Yes==MessageBox::questionYesNo(this, i18n("Reload <b>%1</b> streams?").arg(cat->name))) {
|
||||
StreamsModel::self()->reload(mapped);
|
||||
}
|
||||
}
|
||||
|
||||
void StreamsPage::removeItems()
|
||||
{
|
||||
if (!StreamsModel::self()->isFavoritesWritable()) {
|
||||
@@ -378,11 +403,13 @@ void StreamsPage::controlActions()
|
||||
QModelIndexList selected=view->selectedIndexes();
|
||||
editAction->setEnabled(false);
|
||||
addToFavouritesAction->setEnabled(false);
|
||||
if (1==selected.size() && StreamsModel::self()->isFavoritesWritable()) {
|
||||
reloadAction->setEnabled(false);
|
||||
if (1==selected.size()) {
|
||||
const StreamsModel::Item *item=static_cast<const StreamsModel::Item *>(proxy.mapToSource(selected.first()).internalPointer());
|
||||
if (!item->isCategory() && item->parent && item->parent->isFavourites) {
|
||||
if (StreamsModel::self()->isFavoritesWritable() && !item->isCategory() && item->parent && item->parent->isFavourites) {
|
||||
editAction->setEnabled(true);
|
||||
}
|
||||
reloadAction->setEnabled(item->isCategory() && StreamsModel::self()->isTopLevel(static_cast<const StreamsModel::CategoryItem *>(item)));
|
||||
}
|
||||
StdActions::self()->removeAction->setEnabled(false);
|
||||
if (!selected.isEmpty() && StreamsModel::self()->isFavoritesWritable()) {
|
||||
|
||||
@@ -65,6 +65,7 @@ private Q_SLOTS:
|
||||
void exportXml();
|
||||
void add();
|
||||
void addToFavourites();
|
||||
void reload();
|
||||
void edit();
|
||||
void searchItems();
|
||||
void itemDoubleClicked(const QModelIndex &index);
|
||||
@@ -81,6 +82,7 @@ private:
|
||||
Action *addAction;
|
||||
Action *editAction;
|
||||
Action *addToFavouritesAction;
|
||||
Action *reloadAction;
|
||||
StreamsProxyModel proxy;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user