Cache certain stream listings

This commit is contained in:
craig.p.drummond
2013-07-04 19:48:59 +00:00
parent 66241ed93e
commit abc6602b29
6 changed files with 242 additions and 82 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()) {

View File

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