Add option to set stream as favourite

This commit is contained in:
craig
2011-12-14 19:38:56 +00:00
parent f866d00f29
commit 93f1ead73e
9 changed files with 143 additions and 38 deletions

1
TODO
View File

@@ -7,7 +7,6 @@
- Handle xspf/spiff playlists
- Handle more than 1st entry?? Not sure
- Check that MPD can handle protocols before adding
- Add option to makr stream as 'favourite'. If so, place at top of list and show KDE favourite icon
* Library browser
- Have artist icons ?

View File

@@ -42,10 +42,11 @@ StreamDialog::StreamDialog(QWidget *parent)
#endif
{
QWidget *wid = new QWidget(this);
QFormLayout *layout=new QFormLayout(wid);
QFormLayout *layout = new QFormLayout(wid);
nameEntry=new LineEdit(wid);
urlEntry=new LineEdit(wid);
nameEntry = new LineEdit(wid);
urlEntry = new LineEdit(wid);
fav = new QCheckBox(wid);
#ifdef ENABLE_KDE_SUPPORT
layout->setWidget(0, QFormLayout::LabelRole, new QLabel(i18n("Name:"), wid));
#else
@@ -59,7 +60,12 @@ StreamDialog::StreamDialog(QWidget *parent)
#endif
layout->setWidget(1, QFormLayout::FieldRole, urlEntry);
urlEntry->setMinimumWidth(300);
#ifdef ENABLE_KDE_SUPPORT
layout->setWidget(2, QFormLayout::LabelRole, new QLabel(i18n("Favorite:"), wid));
#else
layout->setWidget(2, QFormLayout::LabelRole, new QLabel(tr("Favorite:"), wid));
#endif
layout->setWidget(2, QFormLayout::FieldRole, fav);
#ifdef ENABLE_KDE_SUPPORT
setMainWidget(wid);
setButtons(KDialog::Ok|KDialog::Cancel);
@@ -75,11 +81,13 @@ StreamDialog::StreamDialog(QWidget *parent)
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
#endif
connect(nameEntry, SIGNAL(textChanged(const QString &)), SLOT(textChanged()));
connect(urlEntry, SIGNAL(textChanged(const QString &)), SLOT(textChanged()));
connect(nameEntry, SIGNAL(textChanged(const QString &)), SLOT(changed()));
connect(urlEntry, SIGNAL(textChanged(const QString &)), SLOT(changed()));
connect(fav, SIGNAL(toggled(bool)), SLOT(changed()));
prevFav=false;
}
void StreamDialog::setEdit(const QString &editName, const QString &editUrl)
void StreamDialog::setEdit(const QString &editName, const QString &editUrl, bool f)
{
#ifdef ENABLE_KDE_SUPPORT
setCaption(i18n("Edit Stream"));
@@ -90,15 +98,17 @@ void StreamDialog::setEdit(const QString &editName, const QString &editUrl)
#endif
prevName=editName;
prevUrl=editUrl;
prevFav=f;
nameEntry->setText(editName);
urlEntry->setText(editUrl);
fav->setChecked(f);
}
void StreamDialog::textChanged()
void StreamDialog::changed()
{
QString n=name();
QString u=url();
bool enableOk=!n.isEmpty() && !u.isEmpty() && (n!=prevName || u!=prevUrl);
bool enableOk=!n.isEmpty() && !u.isEmpty() && (n!=prevName || u!=prevUrl || fav->isChecked()!=prevFav);
#ifdef ENABLE_KDE_SUPPORT
enableButton(KDialog::Ok, enableOk);
#else

View File

@@ -31,6 +31,7 @@
class QDialogButtonBox;
#endif
#include "lineedit.h"
#include <QtGui/QCheckBox>
#ifdef ENABLE_KDE_SUPPORT
class StreamDialog : public KDialog
@@ -43,22 +44,25 @@ class StreamDialog : public QDialog
public:
StreamDialog(QWidget *parent);
void setEdit(const QString &editName, const QString &editUrl);
void setEdit(const QString &editName, const QString &editUrl, bool f);
QString name() { return nameEntry->text().trimmed(); }
QString url() { return urlEntry->text().trimmed(); }
QString name() const { return nameEntry->text().trimmed(); }
QString url() const { return urlEntry->text().trimmed(); }
bool favorite() const { return fav->isChecked(); }
private Q_SLOTS:
void textChanged();
void changed();
private:
QString prevName;
QString prevUrl;
bool prevFav;
#ifndef ENABLE_KDE_SUPPORT
QDialogButtonBox *buttonBox;
#endif
LineEdit *nameEntry;
LineEdit *urlEntry;
QCheckBox *fav;
};
#endif

View File

@@ -54,18 +54,27 @@ StreamsPage::StreamsPage(MainWindow *p)
removeAction->setText(i18n("Remove Stream"));
editAction = p->actionCollection()->addAction("editstream");
editAction->setText(i18n("Edit Stream"));
editAction = p->actionCollection()->addAction("editstream");
editAction->setText(i18n("Edit Stream"));
markAsFavAction = p->actionCollection()->addAction("markasfav");
markAsFavAction->setText(i18n("Set As Favorite"));
unMarkAsFavAction = p->actionCollection()->addAction("unmarkasfav");
unMarkAsFavAction->setText(i18n("Unset As Favorite"));
#else
importAction = new QAction(tr("Import Streams"), this);
exportAction = new QAction(tr("Export Streams"), this);
addAction = new QAction(tr("Add Stream"), this);
removeAction = new QAction(tr("Remove Stream"), this);
editAction = new QAction(tr("Rename Stream"), this);
markAsFavAction = new QAction(tr("Set As Favorite"), this);
unMarkAsFavAction = new QAction(tr("Unset As Favorite"), this);
#endif
importAction->setIcon(QIcon::fromTheme("document-import"));
exportAction->setIcon(QIcon::fromTheme("document-export"));
addAction->setIcon(QIcon::fromTheme("list-add"));
removeAction->setIcon(QIcon::fromTheme("list-remove"));
editAction->setIcon(QIcon::fromTheme("document-edit"));
markAsFavAction->setIcon(QIcon::fromTheme("emblem-favorite"));
importStreams->setDefaultAction(importAction);
exportStreams->setDefaultAction(exportAction);
addStream->setDefaultAction(addAction);
@@ -84,7 +93,9 @@ StreamsPage::StreamsPage(MainWindow *p)
connect(editAction, SIGNAL(triggered(bool)), this, SLOT(edit()));
connect(importAction, SIGNAL(triggered(bool)), this, SLOT(importXml()));
connect(exportAction, SIGNAL(triggered(bool)), this, SLOT(exportXml()));
connect(view, SIGNAL(itemsSelected(bool)), SLOT(controlEdit()));
connect(markAsFavAction, SIGNAL(triggered(bool)), this, SLOT(markAsFav()));
connect(unMarkAsFavAction, SIGNAL(triggered(bool)), this, SLOT(unMarkAsFav()));
connect(view, SIGNAL(itemsSelected(bool)), SLOT(controlActions()));
importStreams->setAutoRaise(true);
exportStreams->setAutoRaise(true);
addStream->setAutoRaise(true);
@@ -109,6 +120,8 @@ StreamsPage::StreamsPage(MainWindow *p)
view->addAction(editAction);
view->addAction(removeAction);
view->addAction(exportAction);
view->addAction(markAsFavAction);
view->addAction(unMarkAsFavAction);
proxy.setSourceModel(&model);
view->setModel(&proxy);
}
@@ -212,7 +225,7 @@ void StreamsPage::add()
return;
}
if (!model.add(name, url)) {
if (!model.add(name, url, dlg.favorite())) {
#ifdef ENABLE_KDE_SUPPORT
KMessageBox::error(this, i18n("A stream named <i>%1</i> already exists!", name));
#else
@@ -268,17 +281,19 @@ void StreamsPage::edit()
StreamDialog dlg(this);
QModelIndex index=proxy.mapToSource(selected.first());
QString name=model.data(index, Qt::DisplayRole).toString();
QString url=model.data(index, Qt::ToolTipRole).toString();
StreamsModel::Stream *stream=static_cast<StreamsModel::Stream *>(index.internalPointer());
QString name=stream->name;
QString url=stream->url.toString();
bool fav=stream->favorite;
dlg.setEdit(name, url);
dlg.setEdit(name, url, fav);
if (QDialog::Accepted==dlg.exec()) {
QString newName=dlg.name();
QString newUrl=dlg.url();
QString existingNameForUrl=newUrl!=url ? model.name(newUrl) : QString();
//
if (!existingNameForUrl.isEmpty()) {
#ifdef ENABLE_KDE_SUPPORT
KMessageBox::error(this, i18n("Stream already exists!<br/><i>%1</i>", existingNameForUrl));
@@ -292,17 +307,47 @@ void StreamsPage::edit()
QMessageBox::critical(this, tr("Error"), tr("A stream named <i>%1</i> already exists!").arg(newName));
#endif
} else {
model.edit(index, newName, newUrl);
model.edit(index, newName, newUrl, dlg.favorite());
}
}
}
void StreamsPage::controlEdit()
void StreamsPage::controlActions()
{
editAction->setEnabled(1==view->selectionModel()->selectedIndexes().size());
QModelIndexList selected=view->selectionModel()->selectedIndexes();
editAction->setEnabled(1==selected.size());
bool doneMark=false, doneUnMark=false;
markAsFavAction->setEnabled(false);
unMarkAsFavAction->setEnabled(false);
foreach (const QModelIndex &idx, selected) {
QModelIndex index=proxy.mapToSource(idx);
StreamsModel::Stream *stream=static_cast<StreamsModel::Stream *>(index.internalPointer());
if (stream->favorite) {
unMarkAsFavAction->setEnabled(true);
doneUnMark=true;
} else {
markAsFavAction->setEnabled(true);
doneMark=true;
}
if (doneUnMark && doneMark) {
break;
}
}
}
void StreamsPage::searchItems()
{
proxy.setFilterRegExp(search->text());
}
void StreamsPage::mark(bool f)
{
QModelIndexList selected=view->selectionModel()->selectedIndexes();
QList<int> rows;
foreach (const QModelIndex &idx, selected) {
QModelIndex index=proxy.mapToSource(idx);
rows << index.row();
}
model.mark(rows, f);
}

View File

@@ -50,8 +50,11 @@ private Q_SLOTS:
void add();
void remove();
void edit();
void controlEdit();
void controlActions();
void searchItems();
void markAsFav() { mark(true); }
void unMarkAsFav() { mark(false); }
void mark(bool f);
private:
Action *importAction;
@@ -59,6 +62,8 @@ private:
Action *addAction;
Action *removeAction;
Action *editAction;
Action *markAsFavAction;
Action *unMarkAsFavAction;
StreamsModel model;
StreamsProxyModel proxy;
};

View File

@@ -31,11 +31,11 @@
#include <QtCore/QFile>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>
#include <QtGui/QIcon>
#include "streamsmodel.h"
#include "settings.h"
#include "playlisttablemodel.h"
#include "config.h"
#include <QtCore/QDebug>
static QString configDir()
{
@@ -70,6 +70,16 @@ int StreamsModel::rowCount(const QModelIndex &) const
return items.size();
}
QModelIndex StreamsModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(parent)
if(row<items.count())
return createIndex(row, column, (void *)&items.at(row));
return QModelIndex();
}
QVariant StreamsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
@@ -80,10 +90,15 @@ QVariant StreamsModel::data(const QModelIndex &index, int role) const
return QVariant();
}
if (Qt::DisplayRole == role) {
return items.at(index.row()).name;
} else if(Qt::ToolTipRole == role) {
return items.at(index.row()).url;
switch(role) {
case Qt::DisplayRole: return items.at(index.row()).name;
case Qt::ToolTipRole: return items.at(index.row()).url;
case Qt::UserRole: return items.at(index.row()).favorite;
case Qt::DecorationRole:
if (items.at(index.row()).favorite) {
return QIcon::fromTheme("emblem-favorite");
}
default: break;
}
return QVariant();
@@ -127,7 +142,7 @@ bool StreamsModel::load(const QString &filename, bool isInternal)
bool haveInserted=false;
doc.setContent(&file);
QDomElement root = doc.documentElement();
qWarning() << root.elementsByTagName("stream").count();
if ("cantata" == root.tagName() && root.hasAttribute("version") && "1.0" == root.attribute("version")) {
QDomElement stream = root.firstChildElement("stream");
while (!stream.isNull()) {
@@ -135,6 +150,7 @@ bool StreamsModel::load(const QString &filename, bool isInternal)
QString name=stream.attribute("name");
QString origName=name;
QUrl url=QUrl(stream.attribute("url"));
bool fav=stream.hasAttribute("favorite") ? stream.attribute("favorite")=="true" : false;
if (!entryExists(QString(), url)) {
int i=1;
@@ -149,7 +165,7 @@ bool StreamsModel::load(const QString &filename, bool isInternal)
}
haveInserted=true;
}
items.append(Stream(name, url));
items.append(Stream(name, url, fav));
itemMap.insert(url.toString(), name);
}
}
@@ -181,6 +197,9 @@ bool StreamsModel::save(const QString &filename)
QDomElement stream = doc.createElement("stream");
stream.setAttribute("name", s.name);
stream.setAttribute("url", s.url.toString());
if (s.favorite) {
stream.setAttribute("favorite", "true");
}
root.appendChild(stream);
}
@@ -188,7 +207,7 @@ bool StreamsModel::save(const QString &filename)
return true;
}
bool StreamsModel::add(const QString &name, const QString &url)
bool StreamsModel::add(const QString &name, const QString &url, bool fav)
{
QUrl u(url);
@@ -199,7 +218,7 @@ bool StreamsModel::add(const QString &name, const QString &url)
// int row=items.count();
beginResetModel();
// beginInsertRows(createIndex(0, 0), row, row); // ????
items.append(Stream(name, u));
items.append(Stream(name, u, fav));
itemMap.insert(url, name);
// endInsertRows();
// emit layoutChanged();
@@ -210,7 +229,7 @@ bool StreamsModel::add(const QString &name, const QString &url)
return true;
}
void StreamsModel::edit(const QModelIndex &index, const QString &name, const QString &url)
void StreamsModel::edit(const QModelIndex &index, const QString &name, const QString &url, bool fav)
{
QUrl u(url);
int row=index.row();
@@ -221,7 +240,7 @@ void StreamsModel::edit(const QModelIndex &index, const QString &name, const QSt
items.removeAt(index.row());
itemMap.remove(old.url.toString());
row=items.count();
items.append(Stream(name, u));
items.append(Stream(name, u, fav));
itemMap.insert(url, name);
endResetModel();
save();
@@ -296,3 +315,12 @@ void StreamsModel::persist()
{
save(getInternalFile());
}
void StreamsModel::mark(const QList<int> &rows, bool f)
{
beginResetModel();
foreach (int r, rows) {
items[r].favorite=f;
}
endResetModel();
}

View File

@@ -37,27 +37,30 @@ class StreamsModel : public QAbstractListModel
public:
struct Stream
{
Stream(const QString &n, const QUrl &u) : name(n), url(u) { }
Stream(const QString &n, const QUrl &u, bool fav) : name(n), url(u), favorite(fav) { }
QString name;
QUrl url;
bool favorite;
};
StreamsModel();
~StreamsModel();
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QModelIndex index(int row, int column, const QModelIndex &parent) const;
QVariant data(const QModelIndex &, int) const;
void reload();
void save(bool force=false);
bool save(const QString &filename);
bool import(const QString &filename) { return load(filename, false); }
bool add(const QString &name, const QString &url);
void edit(const QModelIndex &index, const QString &name, const QString &url);
bool add(const QString &name, const QString &url, bool fav);
void edit(const QModelIndex &index, const QString &name, const QString &url, bool fav);
void remove(const QModelIndex &index);
QString name(const QString &url);
bool entryExists(const QString &name, const QUrl &url=QUrl());
Qt::ItemFlags flags(const QModelIndex &index) const;
QMimeData * mimeData(const QModelIndexList &indexes) const;
void mark(const QList<int> &rows, bool f);
private:
bool load(const QString &filename, bool isInternal);

View File

@@ -21,6 +21,7 @@
* Boston, MA 02110-1301, USA.
*/
#include "streamsproxymodel.h"
#include "streamsmodel.h"
StreamsProxyModel::StreamsProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
{
@@ -30,3 +31,12 @@ StreamsProxyModel::StreamsProxyModel(QObject *parent) : QSortFilterProxyModel(pa
setSortLocaleAware(true);
sort(0);
}
bool StreamsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
StreamsModel::Stream *l=static_cast<StreamsModel::Stream *>(left.internalPointer());
StreamsModel::Stream *r=static_cast<StreamsModel::Stream *>(right.internalPointer());
return l->favorite > r->favorite
|| (l->favorite==r->favorite && l->name.localeAwareCompare(r->name)<0);
}

View File

@@ -30,6 +30,7 @@ class StreamsProxyModel : public QSortFilterProxyModel
{
public:
StreamsProxyModel(QObject *parent = 0);
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
};
#endif