Add option to set stream as favourite
This commit is contained in:
1
TODO
1
TODO
@@ -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 ?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ class StreamsProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
StreamsProxyModel(QObject *parent = 0);
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user