Bookmark tuneIn categories

BUG:252
This commit is contained in:
craig.p.drummond
2013-07-09 14:12:51 +00:00
committed by craig.p.drummond
parent cdb9a7e9e8
commit bb69a08634
4 changed files with 274 additions and 13 deletions

View File

@@ -131,6 +131,11 @@ static QString categoryCacheName(const QString &name, bool createDir=false)
return Utils::cacheDir(StreamsModel::constCacheDir, createDir)+name+StreamsModel::constCacheExt;
}
static QString categoryBookmarksName(const QString &name, bool createDir=false)
{
return Utils::configDir(QLatin1String("bookmarks"), createDir)+name+StreamsModel::constCacheExt;
}
void StreamsModel::CategoryItem::removeCache()
{
if (childrenHaveCache) {
@@ -147,6 +152,97 @@ void StreamsModel::CategoryItem::removeCache()
}
}
void StreamsModel::CategoryItem::removeBookmarks()
{
if (bookmarksName.isEmpty()) {
return;
}
QString fileName=categoryBookmarksName(bookmarksName);
if (QFile::exists(fileName)) {
QFile::remove(fileName);
}
}
void StreamsModel::CategoryItem::saveBookmarks()
{
if (bookmarksName.isEmpty() || !supportsBookmarks) {
return;
}
foreach (Item *child, children) {
if (child->isCategory()) {
CategoryItem *cat=static_cast<CategoryItem *>(child);
if (cat->isBookmarks) {
if (cat->children.count()) {
QFile file(categoryBookmarksName(bookmarksName, true));
QtIOCompressor compressor(&file);
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
if (compressor.open(QIODevice::WriteOnly)) {
QXmlStreamWriter doc(&compressor);
doc.writeStartDocument();
doc.writeStartElement("bookmarks");
doc.writeAttribute("version", "1.0");
doc.setAutoFormatting(false);
foreach (Item *i, cat->children) {
doc.writeStartElement("bookmark");
doc.writeAttribute("name", i->name);
doc.writeAttribute("url", i->url);
doc.writeEndElement();
}
doc.writeEndElement();
doc.writeEndElement();
}
}
break;
}
}
}
}
QList<StreamsModel::Item *> StreamsModel::CategoryItem::loadBookmarks()
{
QList<Item *> newItems;
if (bookmarksName.isEmpty() || !supportsBookmarks) {
return newItems;
}
QString fileName=categoryBookmarksName(bookmarksName);
if (!QFile::exists(fileName)) {
return newItems;
}
QFile file(fileName);
QtIOCompressor compressor(&file);
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
if (compressor.open(QIODevice::ReadOnly)) {
QXmlStreamReader doc(&compressor);
while (!doc.atEnd()) {
doc.readNext();
if (doc.isStartElement() && QLatin1String("bookmark")==doc.name()) {
QString name=doc.attributes().value("name").toString();
QString url=doc.attributes().value("url").toString();
if (!name.isEmpty() && !url.isEmpty()) {
newItems.append(new CategoryItem(url, name, this));
}
}
}
}
return newItems;
}
StreamsModel::CategoryItem * StreamsModel::CategoryItem::createBookmarksCategory()
{
Icon icon=Icon("bookmarks");
if (icon.isNull()) {
icon=Icon("user-bookmarks");
}
CategoryItem *bookmarkCat = new CategoryItem(QString(), i18n("Bookmarks"), this, icon);
bookmarkCat->state=CategoryItem::Fetched;
bookmarkCat->isBookmarks=true;
return bookmarkCat;
}
StreamsModel::StreamsModel(QObject *parent)
: ActionModel(parent)
, root(new CategoryItem(QString(), "root"))
@@ -155,7 +251,9 @@ StreamsModel::StreamsModel(QObject *parent)
, favouritesModified(false)
, favouritesSaveTimer(0)
{
root->children.append(new CategoryItem(constRadioTimeUrl+QLatin1String("?locale=")+QLocale::system().name(), i18n("TuneIn"), root, getIcon("tunein")));
CategoryItem *tuneIn=new CategoryItem(constRadioTimeUrl+QLatin1String("?locale=")+QLocale::system().name(), i18n("TuneIn"), root, getIcon("tunein"), QString(), "tunein");
tuneIn->supportsBookmarks=true;
root->children.append(tuneIn);
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"), "somafm"));
@@ -469,6 +567,92 @@ void StreamsModel::updateFavouriteStream(Item *item)
emit dataChanged(index, index);
}
void StreamsModel::addBookmark(const QModelIndex &index)
{
Item *item=toItem(index);
if (item!=root && item->isCategory() && !item->url.isEmpty() && !root->children.contains(item) && static_cast<CategoryItem *>(item)->canBookmark) {
CategoryItem *cat=item->parent;
CategoryItem *bookmarkParentCat=0;
while (cat && !bookmarkParentCat) {
if (cat->supportsBookmarks) {
bookmarkParentCat=cat;
}
cat=cat->parent;
}
if (bookmarkParentCat) {
CategoryItem *bookmarkCat=0;
foreach (Item *i, bookmarkParentCat->children) {
if (i->isCategory() && static_cast<CategoryItem *>(i)->isBookmarks) {
bookmarkCat=static_cast<CategoryItem *>(i);
break;
}
}
if (!bookmarkCat) {
QModelIndex index=createIndex(bookmarkParentCat->parent->children.indexOf(bookmarkParentCat), 0, (void *)bookmarkParentCat);
beginInsertRows(index, bookmarkParentCat->children.count(), bookmarkParentCat->children.count());
bookmarkCat=bookmarkParentCat->createBookmarksCategory();
bookmarkParentCat->children.append(bookmarkCat);
endInsertRows();
}
foreach (Item *i, bookmarkCat->children) {
if (i->url==item->url) {
return;
}
}
QModelIndex index=createIndex(bookmarkCat->parent->children.indexOf(bookmarkCat), 0, (void *)bookmarkCat);
beginInsertRows(index, bookmarkCat->children.count(), bookmarkCat->children.count());
bookmarkCat->children.append(new CategoryItem(item->url, item->name, bookmarkCat));
endInsertRows();
bookmarkParentCat->saveBookmarks();
}
}
}
void StreamsModel::removeBookmark(const QModelIndex &index)
{
Item *item=toItem(index);
if (item->isCategory() && item->parent && item->parent->isBookmarks) {
CategoryItem *bookmarkCat=item->parent; // 'Bookmarks'
CategoryItem *cat=bookmarkCat->parent; // e.g. 'TuneIn'
if (1==bookmarkCat->children.count()) { // Only 1 bookark, so remove 'Bookmarks' folder...
int pos=cat->children.indexOf(bookmarkCat);
QModelIndex index=createIndex(cat->parent->children.indexOf(cat), 0, (void *)cat);
beginRemoveRows(index, pos, pos);
delete cat->children.takeAt(pos);
endRemoveRows();
cat->removeBookmarks();
} else if (!bookmarkCat->children.isEmpty()) { // More than 1 bookmark...
int pos=bookmarkCat->children.indexOf(item);
QModelIndex index=createIndex(bookmarkCat->parent->children.indexOf(bookmarkCat), 0, (void *)bookmarkCat);
beginRemoveRows(index, pos, pos);
delete bookmarkCat->children.takeAt(pos);
endRemoveRows();
cat->saveBookmarks();
}
}
}
void StreamsModel::removeAllBookmarks(const QModelIndex &index)
{
Item *item=toItem(index);
if (item->isCategory() && static_cast<CategoryItem *>(item)->isBookmarks) {
CategoryItem *cat=item->parent; // e.g. 'TuneIn'
int pos=cat->children.indexOf(item);
QModelIndex index=createIndex(cat->parent->children.indexOf(cat), 0, (void *)cat);
beginRemoveRows(index, pos, pos);
delete cat->children.takeAt(pos);
endRemoveRows();
cat->removeBookmarks();
}
}
bool StreamsModel::importXml(const QString &fileName)
{
return loadXml(fileName, createIndex(root->children.indexOf(favourites), 0, favourites));
@@ -611,6 +795,18 @@ void StreamsModel::jobFinished()
saveCache(cat, newItems);
}
if (cat && cat->parent==root && cat->supportsBookmarks) {
QList<Item *> bookmarks=cat->loadBookmarks();
if (bookmarks.count()) {
CategoryItem *bookmarksCat=cat->createBookmarksCategory();
foreach (Item *i, bookmarks) {
i->parent=bookmarksCat;
}
bookmarksCat->children=bookmarks;
newItems.append(bookmarksCat);
}
}
if (!newItems.isEmpty()) {
beginInsertRows(index, cat->children.count(), (cat->children.count()+newItems.count())-1);
cat->children+=newItems;
@@ -657,6 +853,7 @@ QList<StreamsModel::Item *> StreamsModel::parseRadioTimeResponse(QIODevice *dev,
}
}
}
return newItems;
}
@@ -1137,7 +1334,9 @@ StreamsModel::Item * StreamsModel::parseRadioTimeEntry(QXmlStreamReader &doc, Ca
if (isStation) {
item=new Item(url, text, parent);
} else {
item=cat=new CategoryItem(url, text, parent);
cat=new CategoryItem(url, text, parent);
cat->canBookmark=!url.isEmpty();
item=cat;
}
}
}
@@ -1316,6 +1515,9 @@ static void saveStream(QXmlStreamWriter &doc, const StreamsModel::Item *item)
static void saveCategory(QXmlStreamWriter &doc, const StreamsModel::CategoryItem *cat)
{
if (cat->isBookmarks) {
return;
}
doc.writeStartElement("category");
doc.writeAttribute("name", cat->name);
if (cat->isAll) {

View File

@@ -60,18 +60,28 @@ public:
Fetched
};
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), childrenHaveCache(false), icon(i), cacheName(cn) { }
CategoryItem(const QString &u, const QString &n=QString(), CategoryItem *p=0, const QIcon &i=QIcon(),
const QString &cn=QString(), const QString &bn=QString())
: Item(u, n, p), state(Initial), isFavourites(false), isAll(false), isBookmarks(false),
childrenHaveCache(false), supportsBookmarks(false), canBookmark(false), icon(i), cacheName(cn), bookmarksName(bn) { }
virtual ~CategoryItem() { qDeleteAll(children); }
virtual bool isCategory() const { return true; }
void removeCache();
void removeBookmarks();
void saveBookmarks();
QList<Item *> loadBookmarks();
CategoryItem *createBookmarksCategory();
State state;
bool isFavourites : 1;
bool isAll : 1;
bool childrenHaveCache : 1;
bool isBookmarks : 1; // 'Virtual' bookmarks category...
bool childrenHaveCache : 1; // Only used for ListenLive - as each sub-category can have the cache
bool supportsBookmarks : 1; // Intended for top-level items, indicates if bookmarks can be added
bool canBookmark : 1; // Can this category be bookmark'ed in top-level parent?
QList<Item *> children;
QIcon icon;
QString cacheName;
QString bookmarksName;
};
static const QString constPrefix;
@@ -108,6 +118,10 @@ public:
bool nameExistsInFavourites(const QString &n);
void updateFavouriteStream(Item *item);
void addBookmark(const QModelIndex &index);
void removeBookmark(const QModelIndex &index);
void removeAllBookmarks(const QModelIndex &index);
bool importXml(const QString &fileName);
bool saveXml(const QString &fileName, const QList<Item *> &items, bool format=true);

View File

@@ -59,6 +59,7 @@ StreamsPage::StreamsPage(QWidget *p)
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);
addBookmarkAction = ActionCollection::get()->createAction("bookmarkcategory", i18n("Bookmark Category"), Icon("bookmark-new"));
Action *settingsAct = new Action(i18n("Digitally Imported Settings"), this);
replacePlayQueue->setDefaultAction(StdActions::self()->replacePlayQueueAction);
Action *searchAction = ActionCollection::get()->createAction("searchtunein", i18n("Search for Radio Stations via TuneIn"), Icons::self()->searchIcon);
@@ -67,6 +68,7 @@ StreamsPage::StreamsPage(QWidget *p)
connect(view, SIGNAL(searchItems()), this, SLOT(searchItems()));
connect(view, SIGNAL(itemsSelected(bool)), SLOT(controlActions()));
connect(addAction, SIGNAL(triggered(bool)), this, SLOT(add()));
connect(addBookmarkAction, SIGNAL(triggered(bool)), this, SLOT(addBookmark()));
connect(addToFavouritesAction, SIGNAL(triggered(bool)), this, SLOT(addToFavourites()));
connect(reloadAction, SIGNAL(triggered(bool)), this, SLOT(reload()));
connect(editAction, SIGNAL(triggered(bool)), this, SLOT(edit()));
@@ -102,6 +104,7 @@ StreamsPage::StreamsPage(QWidget *p)
view->addAction(editAction);
view->addAction(StdActions::self()->removeAction);
view->addAction(addToFavouritesAction);
view->addAction(addBookmarkAction);
view->addAction(reloadAction);
proxy.setSourceModel(StreamsModel::self());
view->setModel(&proxy);
@@ -271,6 +274,17 @@ void StreamsPage::add()
exportAction->setEnabled(StreamsModel::self()->haveFavourites());
}
void StreamsPage::addBookmark()
{
QModelIndexList selected = view->selectedIndexes();
if (1!=selected.count()) {
return;
}
StreamsModel::self()->addBookmark(proxy.mapToSource(selected.first()));
}
void StreamsPage::addToFavourites()
{
if (!StreamsModel::self()->isFavoritesWritable()) {
@@ -316,11 +330,32 @@ void StreamsPage::reload()
void StreamsPage::removeItems()
{
QModelIndexList selected = view->selectedIndexes();
if (1==selected.count()) {
QModelIndex mapped=proxy.mapToSource(selected.first());
const StreamsModel::Item *item=static_cast<const StreamsModel::Item *>(mapped.internalPointer());
if (item->isCategory() && item->parent) {
if (item->parent->isBookmarks) {
if (MessageBox::No==MessageBox::warningYesNo(this, i18n("Are you sure you wish to remove bookmark to <b>%1</b>?").arg(item->name))) {
return;
}
StreamsModel::self()->removeBookmark(mapped);
return;
} else if (static_cast<const StreamsModel::CategoryItem *>(item)->isBookmarks) {
if (MessageBox::No==MessageBox::warningYesNo(this, i18n("Are you sure you wish to remove all <b>%1</b> bookmarks?").arg(item->parent->name))) {
return;
}
StreamsModel::self()->removeAllBookmarks(mapped);
return;
}
}
}
if (!StreamsModel::self()->isFavoritesWritable()) {
return;
}
QModelIndexList selected = view->selectedIndexes();
QModelIndexList useable;
foreach (const QModelIndex &i, selected) {
@@ -334,6 +369,7 @@ void StreamsPage::removeItems()
if (useable.isEmpty()) {
return;
}
if (useable.size()>1) {
if (MessageBox::No==MessageBox::warningYesNo(this, i18n("Are you sure you wish to remove the %1 selected streams?").arg(useable.size()))) {
return;
@@ -407,14 +443,8 @@ void StreamsPage::controlActions()
QModelIndexList selected=view->selectedIndexes();
editAction->setEnabled(false);
addToFavouritesAction->setEnabled(false);
addBookmarkAction->setEnabled(false);
reloadAction->setEnabled(false);
if (1==selected.size()) {
const StreamsModel::Item *item=static_cast<const StreamsModel::Item *>(proxy.mapToSource(selected.first()).internalPointer());
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()) {
bool enableRemove=true;
@@ -436,6 +466,19 @@ void StreamsPage::controlActions()
StdActions::self()->removeAction->setEnabled(enableRemove);
addToFavouritesAction->setEnabled(enableAddToFav);
}
if (1==selected.size()) {
const StreamsModel::Item *item=static_cast<const StreamsModel::Item *>(proxy.mapToSource(selected.first()).internalPointer());
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)));
addBookmarkAction->setEnabled(item->isCategory() && static_cast<const StreamsModel::CategoryItem *>(item)->canBookmark);
if (!StdActions::self()->removeAction->isEnabled()) {
StdActions::self()->removeAction->setEnabled(item->isCategory() && item->parent &&
(item->parent->isBookmarks || (static_cast<const StreamsModel::CategoryItem *>(item)->isBookmarks)));
}
}
addAction->setEnabled(StreamsModel::self()->isFavoritesWritable());
exportAction->setEnabled(StreamsModel::self()->haveFavourites());
importAction->setEnabled(StreamsModel::self()->isFavoritesWritable());

View File

@@ -64,6 +64,7 @@ private Q_SLOTS:
void importXml();
void exportXml();
void add();
void addBookmark();
void addToFavourites();
void reload();
void edit();
@@ -84,6 +85,7 @@ private:
Action *editAction;
Action *addToFavouritesAction;
Action *reloadAction;
Action *addBookmarkAction;
StreamsProxyModel proxy;
};